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