Check if types are castable / subclasses

后端 未结 6 2229
执笔经年
执笔经年 2020-12-07 00:32

I have they type of two members as strings - and not as a Type instance. How can I check if the two types are castable? Let\'s say string one is \"System.Windows.Forms.Label

6条回答
  •  执笔经年
    2020-12-07 01:13

    I was helped by this discussion, Thanks.

    I modified nawfal's code to solve problem about primitive types.

    Now it returns correct results.

    typeof(short).IsCastableTo(typeof(int)); // True
    typeof(short).IsCastableTo(typeof(int), implicitly:true); // True
    typeof(int).IsCastableTo(typeof(short)); // True
    typeof(int).IsCastableTo(typeof(short), implicitly:true); // False
    

    The code is as below.

    public static bool IsCastableTo(this Type from, Type to, bool implicitly = false)
    {
        return to.IsAssignableFrom(from) || from.HasCastDefined(to, implicitly);
    }
    
    static bool HasCastDefined(this Type from, Type to, bool implicitly)
    {
        if ((from.IsPrimitive || from.IsEnum) && (to.IsPrimitive || to.IsEnum))
        {
            if (!implicitly)
                return from==to || (from!=typeof(Boolean) && to!=typeof(Boolean));
    
            Type[][] typeHierarchy = {
                new Type[] { typeof(Byte),  typeof(SByte), typeof(Char) },
                new Type[] { typeof(Int16), typeof(UInt16) },
                new Type[] { typeof(Int32), typeof(UInt32) },
                new Type[] { typeof(Int64), typeof(UInt64) },
                new Type[] { typeof(Single) },
                new Type[] { typeof(Double) }
            };
            IEnumerable lowerTypes = Enumerable.Empty();
            foreach (Type[] types in typeHierarchy)
            {
                if ( types.Any(t => t == to) )
                    return lowerTypes.Any(t => t == from);
                lowerTypes = lowerTypes.Concat(types);
            }
    
            return false;   // IntPtr, UIntPtr, Enum, Boolean
        }
        return IsCastDefined(to, m => m.GetParameters()[0].ParameterType, _ => from, implicitly, false)
            || IsCastDefined(from, _ => to, m => m.ReturnType, implicitly, true);
    }
    
    static bool IsCastDefined(Type type, Func baseType,
                            Func derivedType, bool implicitly, bool lookInBase)
    {
        var bindinFlags = BindingFlags.Public | BindingFlags.Static
                        | (lookInBase ? BindingFlags.FlattenHierarchy : BindingFlags.DeclaredOnly);
        return type.GetMethods(bindinFlags).Any(
            m => (m.Name=="op_Implicit" || (!implicitly && m.Name=="op_Explicit"))
                && baseType(m).IsAssignableFrom(derivedType(m)));
    }
    

提交回复
热议问题