检查 'T' 是否继承或实现了一个类/接口。

111

有没有办法测试T是否继承/实现了一个类/接口?

private void MyGenericClass<T> ()
{
    if(T ... inherits or implements some class/interface
}

4
这似乎可行...如果(typeof(TestClass).IsAssignableFrom(typeof(T))),能否有人确认我的怀疑?谢谢! - user1229895
我非常确定这个答案已经被重复很多次了! - Felix K.
3
菲利克斯K 即使这个答案已经被复制很多次,它也帮助了很多人很多次;)...就像我五分钟前:) - Samuel
8个回答

164

有一个名为Type.IsAssignableFrom()的方法。

要检查T是否继承/实现Employee

typeof(Employee).IsAssignableFrom(typeof(T));

如果您的目标是 .NET Core,该方法已移动到 TypeInfo:

typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).Ge‌​tTypeInfo())

请注意,如果您希望限制类型T实现某个接口或继承自某个类,则应选择@snajahi的答案,该答案使用编译时检查来实现,并通常类似于更好的解决此问题的方法。

你应该更新你的回答并提供一个例子,例如 typeof(T).IsAssignableFrom(typeof(IMyInterface))。 - Dr. Andrew Burnett-Thompson
没问题,nikeee;旧答案还在那里。 :) 我花了几秒钟来弄清楚问题出在哪里。无论如何,+1,.net框架的又一个不错的功能。 - Samuel
3
虽然这个方法几乎可以正常工作,但是当T被限制为一些其他类型TOther时,执行时typeof(T)实际上会评估为typeof(TOther)而不是你传递的任何类型T,在这种情况下,假设TOther没有实现SomeInterfacetypeof(SomeInterface).IsAssignableFrom(typeof(T))将会失败,即使你的具体类型确实实现了SomeInterface - Dave Cousineau
1
在 .net core 中,TypeInfo 类的 IsAssignableFrom 方法只接受 TypeInfo 作为其唯一参数,因此示例应该如下所示: typeof(Employee).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo()) - To Ka
也许我漏掉了什么,但在 .Net 5 中,IsAssignableFrom 仍然是 Type 类的一部分。 - sw1337
显示剩余4条评论

39

20

如果您想在编译期间进行检查:如果 T 未实现 所需的接口/类,则可以使用以下约束条件来产生错误。

public void MyRestrictedMethod<T>() where T : MyInterface1, MyInterface2, MySuperClass
{
    //Code of my method here, clean without any check for type constraints.
}

我希望你能从中受益。

14
正确的语法是:

typeof(Employee).IsAssignableFrom(typeof(T))

文档

返回值:如果c和当前的Type表示相同的类型,或者当前的Typec的继承层次结构中,或者当前的Typec实现的一个接口,或者c是一个通用类型参数并且当前的Type表示 c 的约束之一,或者c表示一个值类型并且当前的Type表示Nullable<c> (Nullable(Of c) 在Visual Basic中)。如果这些条件都不成立,或者cnull,则为false

来源

解释

如果Employee IsAssignableFrom T,那么T继承自Employee

用法

typeof(T).IsAssignableFrom(typeof(Employee)) 

只有当以下任一条件成立时,返回true

  1. TEmployee表示相同的类型;或者
  2. Employee继承自T

这可能是某些情况下的预期用法,但对于原始问题(以及更常见的用法),要确定T是否继承或实现了某个class/interface,请使用:

typeof(Employee).IsAssignableFrom(typeof(T))

13

所有人真正的意思是:

typeof(BaseType).IsAssignableFrom(typeof(DerivedType)) // => true

因为你可以直接从一个DerivedType的实例分配给一个BaseType的实例:

DerivedType childInstance = new DerivedType();
BaseType parentInstance = childInstance; // okay, assigning base from derived
childInstance = (DerivedType) parentInstance; // not okay, assigning derived from base

何时

public class BaseType {}
public class DerivedType : BaseType {}

如果您对此感到困惑,以下是一些具体的示例:
(通过 LinqPad 提供,因此有 HorizontalRunDump
void Main()
{
    // https://dev59.com/B2gv5IYBdhLWcg3wSe0f

    var b1 = new BaseClass1();

    var c1 = new ChildClass1();
    var c2 = new ChildClass2();
    var nb = new nobase();

    Util.HorizontalRun(
        "baseclass->baseclass,child1->baseclass,baseclass->child1,child2->baseclass,baseclass->child2,nobase->baseclass,baseclass->nobase",
        b1.IsAssignableFrom(typeof(BaseClass1)),
        c1.IsAssignableFrom(typeof(BaseClass1)),
        b1.IsAssignableFrom(typeof(ChildClass1)),
        c2.IsAssignableFrom(typeof(BaseClass1)),
        b1.IsAssignableFrom(typeof(ChildClass2)),
        nb.IsAssignableFrom(typeof(BaseClass1)),
        b1.IsAssignableFrom(typeof(nobase))
        ).Dump("Results");

    var results = new List<string>();
    string test;

    test = "c1 = b1";
    try {
        c1 = (ChildClass1) b1;
        results.Add(test);
    } catch { results.Add("FAIL: " + test); }

    test = "b1 = c1";
    try {
        b1 = c1;
        results.Add(test);
    } catch { results.Add("FAIL: " + test); }

    test = "c2 = b1";
    try {
        c2 = (ChildClass2) b1;
        results.Add(test);
    } catch { results.Add("FAIL: " + test); }

    test = "b1 = c2";
    try {
        b1 = c2;
        results.Add(test);
    } catch { results.Add("FAIL: " + test); }

    results.Dump();
}

// Define other methods and classes here
public static class exts {
    public static bool IsAssignableFrom<T>(this T entity, Type baseType) {
        return typeof(T).IsAssignableFrom(baseType);
    }
}


class BaseClass1 {
    public int id;
}

class ChildClass1 : BaseClass1 {
    public string name;
}

class ChildClass2 : ChildClass1 {
    public string descr;
}

class nobase {
    public int id;
    public string name;
    public string descr;
}

结果

baseclass->baseclass

True

child1->baseclass

False

baseclass->child1

True

child2->baseclass

False

baseclass->child2

True

nobase->baseclass

False

baseclass->nobase

False

  • 失败:c1 = b1
  • b1 = c1
  • 失败:c2 = b1
  • b1 = c2

2

我相信语法是:typeof(Employee).IsAssignableFrom(typeof(T));


这是预期的语法。+1 - Luke Willis

0

判断一个对象 o 是否继承了一个类或实现了一个接口的另一种方法是使用 isas 运算符。

如果你只想知道一个对象是否继承了一个类或实现了一个接口,is 运算符将返回一个布尔值结果:

bool isCompatibleType = (o is BaseType || o is IInterface);

如果你想在测试后使用继承类或实现的接口,as 运算符将执行安全转换,返回对应的继承类或实现的接口的引用(如果兼容),否则返回 null:

BaseType b = o as BaseType; // Null if d does not inherit from BaseType.

IInterface i = o as IInterface; // Null if d does not implement IInterface.

如果你只有类型 T,那么请使用 @nikeee 的答案。

0

虽然像其他人所说的那样,IsAssignableFrom是最好的方法,但如果你只需要检查一个类是否继承自另一个类,typeof(T).BaseType == typeof(SomeClass)也可以胜任。


那会起作用,除非SomeClass并非直接派生自BaseClass - Suncat2000

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接