Ejemplo n.º 1
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);
        }