检查类型是否为可转换/子类

我有两个成员类型作为字符串 – 而不是类型实例。 如何检查这两种类型是否可浇铸? 假设字符串1是“System.Windows.Forms.Label”,另一个是“System.Windows.Forms.Control”。 如何检查第一个是否是第二个的子类(或隐式可转换)? 这可以通过reflection来实现吗?

感谢你的支持!

您似乎应该使用Type.IsAssignableFrom但请仔细注意文档:

public virtual bool IsAssignableFrom(Type c)

如果c和当前的[instance of] Type表示相同的类型,或者当前的[instance of] Typec的inheritance层次结构中,或者当前的[instance of] Typec实现的接口,则为true ,或者如果c是generics类型参数,则当前[ Type ]的实例表示c的约束之一。 如果这些条件都不为true ,或者如果cnull引用(在Visual Basic中为Nothing ,则返回null

特别是:

 class Base { } clase NotABase { public static implicit operator Base(NotABase o) { // } } Console.WriteLine(typeof(Base).IsAssignableFrom(typeof(NotABase))); 

将在控制台上打印False ,即使NotABase是隐式可转换为Base的。 所以,为了处理铸造,我们可以像这样使用reflection:

 static class TypeExtensions { public static bool IsCastableTo(this Type from, Type to) { if (to.IsAssignableFrom(from)) { return true; } var methods = from.GetMethods(BindingFlags.Public | BindingFlags.Static) .Where( m => m.ReturnType == to && (m.Name == "op_Implicit" || m.Name == "op_Explicit") ); return methods.Any(); } } 

用法:

 Console.WriteLine(typeof(string).IsCastableTo(typeof(int))); // false Console.WriteLine(typeof(NotABase).IsCastableTo(typeof(Base))); // true 

并为您的情况

 // from is string representing type name, eg "System.Windows.Forms.Label" // to is string representing type name, eg "System.Windows.Forms.Control" Type fromType = Type.GetType(from); Type toType = Type.GetType(to); bool castable = from.IsCastableTo(to); 

如果你可以将这些字符串转换为Type对象,那么你最好的选择是Type.IsAssignableFrom 。

但请注意,这只会告诉您两个Type实例是否在CLR级别兼容。 这不会考虑用户定义的转换或其他C#语义之类的内容。

我得到了这次讨论的帮助,谢谢。

我修改了nawfal的代码来解决有关原始类型的问题。

现在它返回正确的结果。

 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 

代码如下。

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

怎么样:

 public bool IsCastable(String type0, String type1) { return Type.GetType(type1).IsAssignableFrom(Type.GetType(type0)); } 

这与Jason的答案相同,但解决了他的解决方案的一些问题。

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

这应该处理由于inheritance而产生的情况。 例如:

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

这里隐含的关系是在MammalCar之间,但由于Cow也是Mammal ,因此存在从CowCar的隐式转换。 但是所有的Car都是Vehicle ; 因此Cow会进入Vehicle

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

所以

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

即使CowVehicle之间不存在直接转换运算符,也会打印为true。

对于原始类型,上面的解决方案失败,其中转换直接构建到语言而不是框架 ,所以类似于

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

失败。 Afaik,只有手动处理才有帮助。 您将获得msdn中数值类型和其他基本类型的隐式和显式转换的完整列表。

编辑:

IsCastableTo函数可能会更加“ 干 ”,可能会以降低可读性为代价,但我喜欢它:)

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

最简单的方法是value.GetType()。IsSubclassOf(typeof(Control))基本上,Type.IsSubclassOf方法做你需要的