这与杰森的回答相同,但用他的解决方案解决了一些问题。
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<MethodInfo> 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");
}
这也应该处理由于继承而出现的情况。例如:
class Mammal { public static implicit operator Car (Mammal o) { return null; } }
class Cow : Mammal { }
class Vehicle { }
class Car : Vehicle { }
这里隐式关系在Mammal和Car之间,但由于Cow也是Mammal,所以存在从Cow到Car的隐式转换。但是所有Cars 都是Vehicles;因此Cow 会变成Vehicle。
Cow c = null;
Vehicle v = c; //legal
所以
typeof(Cow).IsCastableTo(typeof(Vehicle)); //true
打印为 true,即使 Cow 和 Vehicle 之间不存在直接转换运算符。
上面的解决方案对于转换直接内置于语言而不是框架的原始类型失败,所以类似于
typeof(short).IsCastableTo(typeof(int));
失败。 Afaik,只有手动处理会有所帮助。您将从 msdn 获得 implicit 和 explicit 数字类型和 other primitive types 转换的完整列表。
编辑:
IsCastableTo 函数可能会稍微多一点“DRY”可能会降低可读性,但我喜欢它 :)
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<MethodInfo, Type> baseType, Func<MethodInfo, Type> 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)));
}