【问题标题】:Find if a class derives from another class which is generic in .NET?查找一个类是否派生自另一个在 .NET 中通用的类?
【发布时间】:2013-03-06 13:43:36
【问题描述】:

我有这样的课:

class A<T>
{

}

我有另一个派生自上述类的类,例如:

class B : A<X>
{

}

X 之上是另一个类。

现在我可以有很多类,比如 B,在这些类中,泛型参数可以是其他类。

我如何确定 B 类的任何实例是否派生自 A 类?

我试过了:

if objB.GetType() is typeof(A<object>) //didn't work, gave false

if objB.GetType() == typeof(A<object>) //didn't work, gave false

if typeof(A<object>).IsAssignableFrom(obj.GetType()) //didn't work, gave false

怎么做?

【问题讨论】:

    标签: .net generics inheritance types


    【解决方案1】:

    这是有问题的;除非您已经知道X,否则没有IsAssignableFrom 测试将在那里工作。您必须执行以下操作:

    static bool IsA(Type type) {
        do {
            type = type.BaseType;
            if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(A<>))
               return true;
        } while(type != null && type != typeof(object));
        return false;
    }
    

    或者也可以得到T:

    static bool IsA(Type type, out Type t)
    {
        do
        {
            type = type.BaseType;
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(A<>))
            {
                t = type.GetGenericArguments()[0];
                return true;
            }
        } while (type != null && type != typeof(object));
        t = null;
        return false;
    }
    

    【讨论】:

      【解决方案2】:

      有点误解了这个问题......这就是我在这种情况下会做的事情 - 但请注意,下面的示例只能工作 1 级深度。如果您认为或知道其他对象将从 B 派生,则循环直到 BaseType 为对象并使用当前类型名称。或者,您可以将 B 封印,使其无法派生。

          public class A<T>
          {
      
          }
      
          public class X
          {
      
          }
      
          public class B : A<X>
          {
      
      
          }
      
      
          void Test()
          {
              B obj = new B();
      
              if(b.GetType().BaseType.Name == "A`1")
              {
                  Consosle.WriteLine(true);
              }
          }
      

      【讨论】:

      • Warning 1 The given expression is never of the provided ('A&lt;object&gt;') type - 甚至编译器都知道这绝不是真的
      • 不,这是因为A&lt;X&gt; 不是A&lt;object&gt;。仅当您提前知道 X 时,您的方法才有效。请参阅“现在我可以拥有许多像 B 这样的类,并且在这些类中,泛型参数可能是其他类。我如何确定像 B 这样的类的任何实例是否派生自类 A?”
      • @MarcGravell - 感谢您指出显而易见的 :) 我误解了 OP 想要什么...
      【解决方案3】:

      哦,这对你来说是一些纯粹的邪恶......利用dynamic劫持反射;这里的关键是dynamic 内置了一些基于类型的缓存,所以它不会每次都做繁重的工作(每种类型只有一次):

      static void Main()
      {
          Console.WriteLine(IsA("abc"));   // False
          Console.WriteLine(IsA(new B())); // True
          Console.WriteLine(IsA(123));     // False
          Console.WriteLine(IsA(new D())); // True - where D : B
      }
      public static bool IsA(object o)
      {
          return (bool)EvilOnlyUseDynamicToCallThis((dynamic)o);
      }
      
      private static bool EvilOnlyUseDynamicToCallThis(object o)
      {
          return false;
      }
      private static bool EvilOnlyUseDynamicToCallThis<T>(A<T> a)
      {
          return true;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-21
        • 1970-01-01
        相关资源
        最近更新 更多