如何检查类型是子类型还是对象的类型?


335

要检查一个类型是否是C#中另一个类型的子类,很简单:

typeof (SubClass).IsSubclassOf(typeof (BaseClass)); // returns true

但是,这将失败:

typeof (BaseClass).IsSubclassOf(typeof (BaseClass)); // returns false

有没有办法在不使用OR运算符或扩展方法的情况下检查类型是否是基类本身的子类或基类?

Answers:


498

显然没有。

选项如下:

Type.IsSubclassOf

正如您已经发现的,如果两种类型相同,则将无法正常工作,这是一个示例LINQPad程序,该程序演示:

void Main()
{
    typeof(Derived).IsSubclassOf(typeof(Base)).Dump();
    typeof(Base).IsSubclassOf(typeof(Base)).Dump();
}

public class Base { }
public class Derived : Base { }

输出:

True
False

这表明Derived是的子类Base,但Base(显然)不是其子类。

Type.IsAssignableFrom

现在,这将回答您的特定问题,但也会给您带来误报。正如埃里克·利珀特(Eric Lippert)在评论中指出的那样,尽管该方法确实会True为上述两个问题返回,但也会True为这些问题返回,您可能不希望这样做:

void Main()
{
    typeof(Base).IsAssignableFrom(typeof(Derived)).Dump();
    typeof(Base).IsAssignableFrom(typeof(Base)).Dump();
    typeof(int[]).IsAssignableFrom(typeof(uint[])).Dump();
}

public class Base { }
public class Derived : Base { }

在这里,您将获得以下输出:

True
True
True

True如果方法回答了所问的问题,则最后一个指示将表明该方法uint[]继承自int[]或它们是同一类型,显然不是这种情况。

所以IsAssignableFrom也不是完全正确的。

isas

“问题”与isas你的问题的背景是,他们会要求你对对象进行操作和写直接在代码中的类型之一,而不是与工作Type对象。

换句话说,它将无法编译:

SubClass is BaseClass
^--+---^
   |
   +-- need object reference here

也不会:

typeof(SubClass) is typeof(BaseClass)
                    ^-------+-------^
                            |
                            +-- need type name here, not Type object

也不会:

typeof(SubClass) is BaseClass
^------+-------^
       |
       +-- this returns a Type object, And "System.Type" does not
           inherit from BaseClass

结论

尽管上述方法可能满足您的需求,但对您问题的唯一正确答案(如我所见)是您将需要进行额外的检查:

typeof(Derived).IsSubclassOf(typeof(Base)) || typeof(Derived) == typeof(Base);

在方法中哪个更有意义:

public bool IsSameOrSubclass(Type potentialBase, Type potentialDescendant)
{
    return potentialDescendant.IsSubclassOf(potentialBase)
           || potentialDescendant == potentialBase;
}

2
谢谢!我将其标记为正确答案(必须再等待8分钟),因为您提到必须取消检查并提供了指向MSDN文档的链接。
Daniel T.

71
注意,这实际上并没有完成问题所要求的;这不能确定一种类型是否是另一种类型的子类,而是一种类型是否与另一种类型兼容。uint数组不是int数组的子类,但是它们是赋值兼容的。IEnumerable <Giraffe>不是IEnumerable <Animal>的子类,但是在v4中它们是赋值兼容的。
埃里克·利珀特

有没有办法像Java这样的方法名呢?```void <?扩展Base> saveObject(?objectToSave)```
Oliver Dixon

2
如何IsInstanceOfType适应呢?
Lennart

将IsSameOrSubclass转换为扩展方法可能很诱人,但我建议不要这样做,因为它读写有点笨拙,而且容易搞乱(颠倒potentialBase和potentialDescendant的顺序可能是致命的)。
jrh



1

如果您尝试在Xamarin Forms PCL项目中执行此操作,则使用的上述解决方案IsAssignableFrom会出现错误:

错误:“类型”不包含“ IsAssignableFrom”的定义,找不到找不到接受“类型”类型第一个参数的扩展方法“ IsAssignableFrom”(您是否缺少using指令或程序集引用?)

因为IsAssignableFrom要一个TypeInfo对象。您可以使用以下GetTypeInfo()方法System.Reflection

typeof(BaseClass).GetTypeInfo().IsAssignableFrom(typeof(unknownType).GetTypeInfo())


0

我正在发布此答案,希望有人与我分享是否以及为什么这不是一个好主意。在我的应用程序中,我具有要检查的Type属性,以确保它是typeof(A)或typeof(B),其中B是从A派生的任何类。所以我的代码是:

public class A
{
}

public class B : A
{
}

public class MyClass
{
    private Type _helperType;
    public Type HelperType
    {
        get { return _helperType; }
        set 
        {
            var testInstance = (A)Activator.CreateInstance(value);
            if (testInstance==null)
                throw new InvalidCastException("HelperType must be derived from A");
            _helperType = value;
        }
    }
}

我觉得我在这里可能有点天真,所以欢迎任何反馈。


2
这个想法有两个问题:1)类型需要一个无参数的构造函数,否则CreateInstance将失败;2)如果无法进行强制转换,则抛出对(A)的强制转换不会返回null;3)您实际上不需要新实例,因此您有无用的分配。可接受的答案更好(尽管不完美)。
马塞尔·波佩斯库

感谢您的反馈。非常有帮助。
baskren

@baskren,也许然后支持他的有用评论。我赞成#1。
Developer63
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.