将 IsAssignableFrom 与“开放”泛型类型一起使用
Posted
技术标签:
【中文标题】将 IsAssignableFrom 与“开放”泛型类型一起使用【英文标题】:Using IsAssignableFrom with 'open' generic types 【发布时间】:2011-07-24 14:16:52 【问题描述】:使用反射,我试图找到从给定基类继承的类型集。很快就弄清楚了简单的类型,但是当涉及到泛型时我被难住了。
对于这段代码,第一个 IsAssignableFrom 返回 true,但第二个返回 false。然而,最终的作业编译得很好。
class class1
class class2 : class1
class generic1<T>
class generic2<T> : generic1<T>
class Program
static void Main(string[] args)
Type c1 = typeof(class1);
Type c2 = typeof(class2);
Console.WriteLine("c1.IsAssignableFrom(c2): 0", c1.IsAssignableFrom(c2));
Type g1 = typeof(generic1<>);
Type g2 = typeof(generic2<>);
Console.WriteLine("g1.IsAssignableFrom(g2): 0", g1.IsAssignableFrom(g2));
generic1<class1> cc = new generic2<class1>();
那么我如何在运行时确定一个泛型类型定义是否派生自另一个?
【问题讨论】:
最终作业只涉及generic2
...
How To Detect If Type is Another Generic Type 的可能重复项
@Daniel Hilgarth - 谢谢!当我在发布之前清理示例代码时,我错过了这一点。当赋值为 generic1generic1<>
不能分配给 generic2<>
一般,这就是你要问的,当你省略对typeof
的调用中的通用参数。只有当generic1
和generic2
的通用参数相同时,它才可赋值。如何解决?请参阅康拉德鲁道夫的回答。
【参考方案1】:
@konrad_ruldolph 的回答大部分是正确的,但它要求您知道基本类型/接口是开放的泛型。我提出了一项改进,将非泛型测试与循环相结合来测试泛型匹配。
public static class Ext
public static bool IsAssignableToGeneric(
this Type assignableFrom,
Type assignableTo)
bool IsType(Type comparand)
=> assignableTo.IsAssignableFrom(comparand)
|| (comparand.IsGenericType
&& comparand.GetGenericTypeDefinition() == assignableTo);
while (assignableFrom != null)
if (IsType(assignableFrom)
|| assignableFrom
.GetInterfaces()
.Any(IsType))
return true;
assignableFrom = assignableFrom.BaseType;
return false;
【讨论】:
【参考方案2】:我的两分钱。恕我直言,分离 IsAssignableFrom 的实现、派生或原始功能没有多大意义,
根据之前给出的答案构建,这就是我的做法:
public static bool ImplementsOrDerives(this Type @this, Type from)
if(from is null)
return false;
else if(!from.IsGenericType)
return from.IsAssignableFrom(@this);
else if(!from.IsGenericTypeDefinition)
return from.IsAssignableFrom(@this);
else if(from.IsInterface)
foreach(Type @interface in @this.GetInterfaces())
if(@interface.IsGenericType && @interface.GetGenericTypeDefinition() == from)
return true;
if(@this.IsGenericType && @this.GetGenericTypeDefinition() == from)
return true;
return @this.BaseType?.ImplementsOrDerives(from) ?? false;
【讨论】:
【参考方案3】:我有一个不同的方法可以解决这个问题,这是我的课程
public class Signal<T>
protected string Id get; set; //This must be here, I use a property because MemberInfo is returned in an array via GetMember() reflection function
//Some Data and Logic And stuff that involves T
public class OnClick : Signal<string>
现在,如果我有一个 OnClick 类型的实例,但我不知道,我想知道我是否有一个从任何类型的 Signal 继承的任何实例?我这样做
Type type = GetTypeWhomISuspectMightBeAGenericSignal();
PropertyInfo secretProperty = type.GetProperty("Id", BindingFlags.NonPublic | BindingFlags.Instance);
Type SpecificGenericType = secretProperty.DeclaringType; //This is the trick
bool IsMyTypeInheriting = SpecificGenericType.IsGenericType && SpecificGenericType.GetGenericTypeDefinition() == typeof(Signal<>); //This way we are getting the genericTypeDefinition and comparing it to any other genericTypeDefinition of the same argument length.
所以这对我有用,它不是递归的,它通过指定属性使用技巧。它的局限性在于很难编写一个检查所有泛型的可分配性的函数。但对于特定类型,它可以工作
显然,您需要更好地检查 if() 条件和其他东西,但这些是评估类型可分配给其基本泛型所需的原始行,以这种方式。
希望对你有帮助
【讨论】:
【参考方案4】:您发布的确切代码不会返回令人惊讶的结果。
这说的是“假”:
Type g1 = typeof(generic1<>);
Type g2 = typeof(generic2<>);
Console.WriteLine("g1.IsAssignableFrom(g2): 0", g1.IsAssignableFrom(g2));
这说的是“真的”:
Type g1 = typeof(generic1<class1>);
Type g2 = typeof(generic2<class1>);
Console.WriteLine("g1.IsAssignableFrom(g2): 0", g1.IsAssignableFrom(g2));
不同之处在于开放的泛型类型不能有实例,因此一个不能“分配”给另一个。
来自docs:
返回
true
如果c
和当前Type
代表相同的类型,或者如果 当前的Type
在c
的继承层次结构,或者如果 当前的Type
是一个接口c
实现,或者如果c
是 泛型类型参数和当前Type
代表其中之一c
的约束。false
如果没有 这些条件为真,或者如果c
是null
。
在这种情况下,显然这些条件都不成立。还有一个额外的说明:
泛型类型定义不是 可从封闭构造分配 类型。也就是说,您不能分配 封闭构造型
MyGenericList<int>
(在 Visual Basic 中为MyGenericList(Of Integer)
)到MyGenericList<T>
类型的变量。
【讨论】:
很好的解释!【参考方案5】:来自answer to another question:
public static bool IsAssignableToGenericType(Type givenType, Type genericType)
var interfaceTypes = givenType.GetInterfaces();
foreach (var it in interfaceTypes)
if (it.IsGenericType && it.GetGenericTypeDefinition() == genericType)
return true;
if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
return true;
Type baseType = givenType.BaseType;
if (baseType == null) return false;
return IsAssignableToGenericType(baseType, genericType);
(如果您喜欢这个答案,请为链接的答案投票,因为代码不是我的。)
【讨论】:
谢谢!这正是我想要的。我之前看的时候没有注意到另一个问题。 在以下情况下,这个方法可能是错误的:IsAssignableToGenericType(typeof(Ais
进行检查...
基于这个方法,我创建了一个不同的方法来获取用于基本类型的通用参数:gist.github.com/2936304
请注意,这比它需要的更昂贵,因为它为每个基本类型迭代接口列表一次,这是不必要的。【参考方案6】:
在以下情况下,使用 Konrad Rudolph 提供的方法可能是错误的,例如:IsAssignableToGenericType(typeof(A), typeof(A));// return false
我认为这是一个更好的答案
public static bool IsAssignableFrom(Type extendType, Type baseType)
while (!baseType.IsAssignableFrom(extendType))
if (extendType.Equals(typeof(object)))
return false;
if (extendType.IsGenericType && !extendType.IsGenericTypeDefinition)
extendType = extendType.GetGenericTypeDefinition();
else
extendType = extendType.BaseType;
return true;
测试用例,详见Using IsAssignableFrom with C# generics
using System;
/**
* Sam Sha - yCoder.com
*
* */
namespace Test2
class MainClass
public static void Main (string[] args)
string a = "ycoder";
Console.WriteLine(a is object);
A aa = new A();
//Console.WriteLine(aa is A<>);//con't write code like this
typeof(A<>).IsAssignableFrom(aa.GetType());//return false
Trace(typeof(object).IsAssignableFrom(typeof(string)));//true
Trace(typeof(A<>).IsAssignableFrom(typeof(A)));//false
AAA aaa = new AAA();
Trace("Use IsTypeOf:");
Trace(IsTypeOf(aaa, typeof(A<>)));
Trace(IsTypeOf(aaa, typeof(AA)));
Trace(IsTypeOf(aaa, typeof(AAA<>)));
Trace("Use IsAssignableFrom from *** - not right:");
Trace(IsAssignableFrom(typeof(A), typeof(A<>))); // error
Trace(IsAssignableFrom(typeof(AA), typeof(A<>)));
Trace(IsAssignableFrom(typeof(AAA), typeof(A<>)));
Trace("Use IsAssignableToGenericType:");
Trace(IsAssignableToGenericType(typeof(A), typeof(A<>)));
Trace(IsAssignableToGenericType(typeof(AA), typeof(A<>)));
Trace(IsAssignableToGenericType(typeof(AAA), typeof(A<>)));
static void Trace(object log)
Console.WriteLine(log);
public static bool IsTypeOf(Object o, Type baseType)
if (o == null || baseType == null)
return false;
bool result = baseType.IsInstanceOfType(o);
if (result)
return result;
return IsAssignableFrom(o.GetType(), baseType);
public static bool IsAssignableFrom(Type extendType, Type baseType)
while (!baseType.IsAssignableFrom(extendType))
if (extendType.Equals(typeof(object)))
return false;
if (extendType.IsGenericType && !extendType.IsGenericTypeDefinition)
extendType = extendType.GetGenericTypeDefinition();
else
extendType = extendType.BaseType;
return true;
//from *** - not good enough
public static bool IsAssignableToGenericType(Type givenType, Type genericType)
var interfaceTypes = givenType.GetInterfaces();
foreach (var it in interfaceTypes)
if (it.IsGenericType)
if (it.GetGenericTypeDefinition() == genericType) return true;
Type baseType = givenType.BaseType;
if (baseType == null) return false;
return baseType.IsGenericType &&
baseType.GetGenericTypeDefinition() == genericType ||
IsAssignableToGenericType(baseType, genericType);
class A
class AA : A
class AAA : AA
【讨论】:
注意:这个答案不处理通用接口。【参考方案7】:您需要比较包含的类型。见:How to get the type of T from a member of a generic class or method?
换句话说,我认为您需要检查泛型类所包含的类型是否是可分配的,而不是泛型类本身。
【讨论】:
以上是关于将 IsAssignableFrom 与“开放”泛型类型一起使用的主要内容,如果未能解决你的问题,请参考以下文章
Class.isAssignableFrom与instanceof的区别
Java isAssignableFrom()方法与instanceof()方法区别