我有两个成员类型作为字符串 - 而不是Type实例。如何检查这两种类型是否可浇铸?假设字符串1是“System.Windows.Forms.Label”,另一个是“System.Windows.Forms.Control”。如何检查第一个是否是第二个的子类(或隐式可转换)?这可以通过反射来实现吗?
感谢您的支持!
答案 0 :(得分:16)
您似乎应该使用Type.IsAssignableFrom
,但请仔细注意文档:
public virtual bool IsAssignableFrom(Type c)
true
如果c
和[{1}}的当前[实例]表示相同类型,或者当前[{1}}的实例位于继承层次结构中Type
,或者Type
的当前[实例]是c
实现的接口,或者Type
是泛型类型参数和当前[实例] { {1}}表示c
的约束之一。c
如果这些条件都不是Type
,或者c
是false
引用(在Visual Basic中为true
)。
特别是:
c
即使null
可隐式转换为Nothing
,也会在控制台上打印class Base { }
clase NotABase { public static implicit operator Base(NotABase o) { // } }
Console.WriteLine(typeof(Base).IsAssignableFrom(typeof(NotABase)));
。因此,为了处理强制转换,我们可以像这样使用反射:
False
用法:
NotABase
对于你的情况
Base
答案 1 :(得分:7)
我在讨论中得到了帮助,谢谢。
我修改了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<Type> lowerTypes = Enumerable.Empty<Type>();
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<MethodInfo, Type> baseType,
Func<MethodInfo, Type> 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)));
}
答案 2 :(得分:6)
如果您可以将这些字符串转换为Type
个对象,那么最好的选择是Type.IsAssignableFrom。
请注意,这只会告诉您两个Type
实例是否在CLR级别兼容。这不会考虑用户定义的转换或其他C#语义之类的内容。
答案 3 :(得分:4)
怎么样:
public bool IsCastable(String type0, String type1)
{
return Type.GetType(type1).IsAssignableFrom(Type.GetType(type0));
}
答案 4 :(得分:2)
这与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<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
。但所有Car
都是Vehicle
s;因此Cow
会进入Vehicle
。
Cow c = null;
Vehicle v = c; //legal
所以
typeof(Cow).IsCastableTo(typeof(Vehicle)); //true
打印为true,即使Cow
和Vehicle
之间不存在直接转换运算符。
上面的解决方案对于原始类型失败,其中转换直接构建到语言而不是框架,所以类似
typeof(short).IsCastableTo(typeof(int));
失败。 Afaik,只有手动处理才有帮助。您将获得数字类型的implicit和explicit转化以及msdn的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)));
}
答案 5 :(得分:1)
最简单的方法是value.GetType()。IsSubclassOf(typeof(Control)) 基本上,Type.IsSubclassOf方法可以满足你的需要