【问题标题】:How do I check if a type is a subtype OR the type of an object?如何检查类型是子类型还是对象的类型?
【发布时间】:2011-02-14 02:20:15
【问题描述】:

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

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

但是,这会失败:

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

有什么方法可以在不使用OR 运算符或扩展方法的情况下检查一个类型是子类还是基类本身?

【问题讨论】:

    标签: c# reflection types subclass


    【解决方案1】:

    显然,没有。

    以下是选项:

    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
    

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

    Type.IsAssignableFrom

    现在,这将回答您的特定问题,但也会给您带来误报。正如 Eric Lippert 在 cmets 中指出的那样,虽然该方法确实会为上述两个问题返回 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;
    }
    

    【讨论】:

    • 谢谢!我会将此标记为正确答案(还要再等 8 分钟),因为您提到必须撤销检查并提供指向 MSDN 文档的链接。
    • 请注意,这实际上并不能满足问题的要求;这并不能确定一种类型是否是另一种类型的子类,而是确定一种类型是否与另一种类型的赋值兼容。 uint 数组不是 int 数组的子类,但它们是赋值兼容的。 IEnumerable 不是 IEnumerable 的子类,但它们在 v4 中是兼容的。
    • IsInstanceOfType 如何适应这个?
    • 为什么typeof(List<object>).IsSubclassOf(typeof(IList<object>))返回false?
    • @NileshBarai 因为类不是它实现的接口的子类。使用typeof(Test).GetInterfaces().Contains(typeof(ITest)) 来测试一个类是否实现了一个接口,或者typeof(ITest).IsAssignableFrom(typeof(Test))
    【解决方案2】:
    typeof(BaseClass).IsAssignableFrom(unknownType);
    

    【讨论】:

      【解决方案3】:

      您应该尝试改用Type.IsAssignableFrom

      【讨论】:

        【解决方案4】:

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

        错误:“类型”不包含“IsAssignableFrom”的定义和 没有扩展方法“IsAssignableFrom”接受第一个参数 可以找到类型“类型”(您是否缺少 using 指令或 汇编参考?)

        因为IsAssignableFrom 要求TypeInfo 对象。 您可以使用来自System.ReflectionGetTypeInfo() 方法:

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

        【讨论】:

          【解决方案5】:

          我发布此答案是希望有人与我分享是否以及为什么这是一个坏主意。在我的应用程序中,我有一个 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;
                  }
              }
          }
          

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

          【讨论】:

          • 这个想法有几个问题:1)类型需要一个无参数的构造函数,否则 CreateInstance 将失败; 2) 如果无法进行转换,则转换为 (A) 不会返回 null,它会抛出; 3)你实际上并不需要新的实例,所以你有一个无用的分配。接受的答案更好(虽然不完美)。
          • 感谢您的反馈。很有帮助。
          猜你喜欢
          • 2020-12-21
          • 2016-11-24
          • 2013-07-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-02-02
          • 2011-09-26
          • 2012-01-10
          相关资源
          最近更新 更多