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)); }
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); }