Beispiel #1
0
        public static Conversion GetExplicit(Operand op, Type to, bool onlyStandard, ITypeMapper typeMapper)
        {
            // try implicit
            Conversion conv = GetImplicit(op, to, onlyStandard, typeMapper);

            if (conv.IsValid)
            {
                return(conv);
            }

            Type from = Operand.GetType(op, typeMapper);

            Type fromUnderlying = Helpers.GetNullableUnderlyingType(@from);

            if (fromUnderlying == to)
            {
                return(new UnwrapNullable(typeMapper));
            }


            Type toUnderlying = Helpers.GetNullableUnderlyingType(to);

            if (toUnderlying != null && fromUnderlying != null)
            {
                var c = GetExplicit(new FakeTypedOperand(fromUnderlying), toUnderlying, onlyStandard, typeMapper);
                if (c.IsValid)
                {
                    return(new ConvertNullable(typeMapper, c));
                }
            }


            // section 6.3.2 - Standard explicit conversions
            if (onlyStandard)
            {
                if (from == null || !GetImplicit(to, @from, true, typeMapper).IsValid)
                {
                    return(new Invalid(typeMapper));
                }
            }

            TypeCode tcFrom = Type.GetTypeCode(from);
            TypeCode tcTo   = Type.GetTypeCode(to);
            byte     ct     = _convTable[(int)tcFrom][(int)tcTo];

            // section 6.2.1 - Explicit numeric conversions, 6.2.2 - Explicit enumeration conversions
            if ((from.IsPrimitive || from.IsEnum || Helpers.AreTypesEqual(from, typeof(decimal), typeMapper)) && (to.IsPrimitive || to.IsEnum || Helpers.AreTypesEqual(to, typeof(decimal), typeMapper)))
            {
                if (ct == D)
                {
                    return(new Direct(typeMapper));                     // this can happen for conversions involving enum-s
                }
                if (ct <= E)
                {
                    if (Helpers.AreTypesEqual(from, typeof(decimal), typeMapper) || Helpers.AreTypesEqual(to, typeof(decimal), typeMapper))
                    {
                        // decimal is handled as user-defined conversion, but as it is a standard one, always enable UDC processing
                        onlyStandard = false;
                    }
                    else
                    {
                        return(new Primitive(typeMapper));
                    }
                }
            }

            // section 6.2.5 - User-defined explicit conversions (details in section 6.4.4)
            if (!(onlyStandard || Helpers.AreTypesEqual(from, typeof(object), typeMapper) || Helpers.AreTypesEqual(to, typeof(object), typeMapper) || from.IsInterface || to.IsInterface ||
                  to.IsSubclassOf(from) || from.IsSubclassOf(to)))
            {
                List <UserDefined> candidates = null;
                FindCandidates(ref candidates, FindExplicitMethods(from, to, typeMapper), op, to, GetExplicit, typeMapper);

                if (candidates != null)
                {
                    if (candidates.Count == 1)
                    {
                        return(candidates[0]);
                    }

                    return(UserDefined.FindExplicit(candidates, @from, to, typeMapper));
                }
            }

            // section 6.2.3 - Explicit reference conversions, 6.2.4 - Unboxing conversions
            // TODO: not really according to spec, but mostly works
            if (!from.IsValueType && from.IsAssignableFrom(to))
            {
                if (to.IsValueType)
                {
                    return(new Unboxing(typeMapper));
                }
                else
                {
                    return(new Cast(typeMapper));
                }
            }

            return(new Invalid(typeMapper));
        }
Beispiel #2
0
        public static Conversion GetExplicit(Operand op, Type to, bool onlyStandard)
        {
            // try implicit
            Conversion conv = GetImplicit(op, to, onlyStandard);

            if (conv.IsValid)
            {
                return(conv);
            }

            Type from = Operand.GetType(op);

            // section 6.3.2 - Standard explicit conversions
            if (onlyStandard)
            {
                if (from == null || !GetImplicit(to, from, true).IsValid)
                {
                    return(Invalid.Instance);
                }
            }

            TypeCode tcFrom = Type.GetTypeCode(from);
            TypeCode tcTo   = Type.GetTypeCode(to);
            byte     ct     = convTable[(int)tcFrom][(int)tcTo];

            // section 6.2.1 - Explicit numeric conversions, 6.2.2 - Explicit enumeration conversions
            if ((from.IsPrimitive || from.IsEnum || from == typeof(decimal)) && (to.IsPrimitive || to.IsEnum || to == typeof(decimal)))
            {
                if (ct == D)
                {
                    return(Direct.Instance);                    // this can happen for conversions involving enum-s
                }
                if (ct <= E)
                {
                    if (from == typeof(decimal) || to == typeof(decimal))
                    {
                        // decimal is handled as user-defined conversion, but as it is a standard one, always enable UDC processing
                        onlyStandard = false;
                    }
                    else
                    {
                        return(Primitive.Instance);
                    }
                }
            }

            // section 6.2.5 - User-defined explicit conversions (details in section 6.4.4)
            if (!(onlyStandard || from == typeof(object) || to == typeof(object) || from.IsInterface || to.IsInterface ||
                  to.IsSubclassOf(from) || from.IsSubclassOf(to)))
            {
                List <UserDefined> candidates = null;
                FindCandidates(ref candidates, FindExplicitMethods(from, to), op, to, GetExplicit);

                if (candidates != null)
                {
                    if (candidates.Count == 1)
                    {
                        return(candidates[0]);
                    }

                    return(UserDefined.FindExplicit(candidates, from, to));
                }
            }

            // section 6.2.3 - Explicit reference conversions, 6.2.4 - Unboxing conversions
            // TODO: not really according to spec, but mostly works
            if (!from.IsValueType && from.IsAssignableFrom(to))
            {
                if (to.IsValueType)
                {
                    return(Unboxing.Instance);
                }
                else
                {
                    return(Cast.Instance);
                }
            }

            return(Invalid.Instance);
        }