Check if types are castable / subclasses

后端 未结 6 2235
执笔经年
执笔经年 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条回答
  •  Happy的楠姐
    2020-12-07 01:25

    This is same as Jason's answer, but solves some problems with his solution.

    public static bool IsCastableTo(this Type from, Type to)
    {
        return to.IsAssignableFrom(from)
            || to.GetConvertOperators().Any(m => m.GetParameters()[0].ParameterType.IsAssignableFrom(from))
            || from.GetConvertOperators(true).Any(m => to.IsAssignableFrom(m.ReturnType));
    }
    
    public static IEnumerable GetConvertOperators(this Type type, bool lookInBase = false)
    {
        var bindinFlags = BindingFlags.Public
                        | BindingFlags.Static
                        | (lookInBase ? BindingFlags.FlattenHierarchy : BindingFlags.DeclaredOnly);
        return type.GetMethods(bindinFlags).Where(m => m.Name == "op_Implicit" || m.Name == "op_Explicit");
    }
    

    This should handle situations that arise due to inheritance as well. For instance:

    class Mammal { public static implicit operator Car (Mammal o) { return null; } }
    class Cow : Mammal { }
    class Vehicle { }
    class Car : Vehicle { }
    

    Here the implicit relationship is between Mammal and Car, but since Cow is Mammal as well, there exist an implicit conversion from Cow to Car. But all Cars are Vehicles; hence a Cow would go into a Vehicle.

    Cow c = null; 
    Vehicle v = c; //legal
    

    So

    typeof(Cow).IsCastableTo(typeof(Vehicle)); //true 
    

    prints true, even though no direct convert operator exist between Cow and Vehicle.

    The solution above fails for primitive types where the conversion is built directly into the language than the framework, so something like

    typeof(short).IsCastableTo(typeof(int));
    

    fails. Afaik, only manually handling will help. You will get complete list of implicit and explicit conversion for numeric types and other primitive types from msdn.

    Edit:

    The IsCastableTo function could be little more "DRY" perhaps at the cost of being less readable, but I like it :)

    public static bool IsCastableTo(this Type from, Type to)
    {
        return to.IsAssignableFrom(from)
            || IsCastDefined(to, m => m.GetParameters()[0].ParameterType, _ => from, false)
            || IsCastDefined(from, _ => to, m => m.ReturnType, true);
    }
    
    //little irrelevant DRY method
    static bool IsCastDefined(Type type, Func baseType, Func derivedType, 
                              bool lookInBase)
    {
        var bindinFlags = BindingFlags.Public
                        | BindingFlags.Static
                        | (lookInBase ? BindingFlags.FlattenHierarchy : BindingFlags.DeclaredOnly);
        return type.GetMethods(bindinFlags).Any(m => (m.Name == "op_Implicit" || m.Name == "op_Explicit") 
                                                  && baseType(m).IsAssignableFrom(derivedType(m)));
    }
    

提交回复
热议问题