检查类型是否为可转换/子类
我有两个成员类型作为字符串 – 而不是类型实例。 如何检查这两种类型是否可浇铸? 假设字符串1是“System.Windows.Forms.Label”,另一个是“System.Windows.Forms.Control”。 如何检查第一个是否是第二个的子类(或隐式可转换)? 这可以通过reflection来实现吗?
感谢你的支持!
您似乎应该使用Type.IsAssignableFrom
但请仔细注意文档:
public virtual bool IsAssignableFrom(Type c)
如果
c
和当前的[instance of]Type
表示相同的类型,或者当前的[instance of]Type
在c
的inheritance层次结构中,或者当前的[instance of]Type
是c
实现的接口,则为true
,或者如果c
是generics类型参数,则当前[Type
]的实例表示c
的约束之一。 如果这些条件都不为true
,或者如果c
是null
引用(在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 { }
这里隐含的关系是在Mammal
和Car
之间,但由于Cow
也是Mammal
,因此存在从Cow
到Car
的隐式转换。 但是所有的Car
都是Vehicle
; 因此Cow
会进入Vehicle
。
Cow c = null; Vehicle v = c; //legal
所以
typeof(Cow).IsCastableTo(typeof(Vehicle)); //true
即使Cow
和Vehicle
之间不存在直接转换运算符,也会打印为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方法做你需要的
上述就是C#学习教程:检查类型是否为可转换/子类分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/955914.html