【问题标题】:C# Type checking for generics [duplicate]泛型的 C# 类型检查 [重复]
【发布时间】:2020-04-26 22:45:58
【问题描述】:

假设我有一堂课

public class Entity<T> { ... // class definition ... }

并说我有一些代码,例如:

var a = new Entity<string>();
var b = new Entity<int>();
var c = new Entity<bool>();
var d = new int;
var e = new List<string>();

无论 T 的类型如何,如何测试对象是否属于“实体”类型?这样:

a is Entity    // true
b is Entity    // true
c is Entity    // true
d is Entity    // false
e is Entity    // false

【问题讨论】:

    标签: c# generics typechecking


    【解决方案1】:

    如果您在想检查它是否是实体时不关心泛型类型,则可以添加一个额外的类。

    public class Entity { } // If you want, you can make it abstract.
    public class Entity<T> : Entity { ... // class definition ... }
    
    var a = new Entity<string>();
    var b = new Entity<int>();
    var c = new Entity<bool>();
    var d = new int;
    var e = new List<string>();
    
    a is Entity    // true
    b is Entity    // true
    c is Entity    // true
    d is Entity    // false
    e is Entity    // false
    

    【讨论】:

      【解决方案2】:

      如果您所处的环境不太关心性能,那么反射可以成为您的解决方案。但是,我建议不要使用反射,而是让 Entity&lt;T&gt; 继承自 EntityIEntity 的非泛型类型(请参阅 Silvermind 的回答)。

      对于反射,这些扩展方法应该允许您检查 typeof(Entity&lt;&gt;)(可选的布尔参数默认也检查基类型):

      static bool IsInstanceOfGenericType(this object item, Type @type, bool includeBaseTypes = true) {
          return item.GetType().IsBasedOnGenericType(@type, includeBaseTypes);
      }
      
      static bool IsBasedOnGenericType(this Type t, Type @type, bool includeBaseTypes = true) {
          return (t.IsGenericType && t.GetGenericTypeDefinition() == @type)
                  || includeBaseTypes
                      && (t.GetInterfaces().Any(i => IsBasedOnGenericType(i, @type))
                          || (t.BaseType != null ? IsBasedOnGenericType(t.BaseType, @type) : false));
      }
      

      IsInstanceOfGenericType 方法可以这样使用:

      class InheritingClass : Entity<string> { }
      class Entity<T> : IEntity<T> { }
      interface IEntity<T> { }
      

      var item = new InheritingClass();
      var item2 = new Entity<string>();
      var item3 = new Entity<string>();
      var item4 = new List<string>();
      var item5 = new InheritingClass();
      
      Console.WriteLine( "item: " + item.IsInstanceOfGenericType(typeof(Entity<>)) );
      Console.WriteLine( "item2: " + item2.IsInstanceOfGenericType(typeof(Entity<>)) );
      Console.WriteLine( "item3: " + item3.IsInstanceOfGenericType(typeof(IEntity<>)) );
      Console.WriteLine( "item4: " + item4.IsInstanceOfGenericType(typeof(IEntity<>)) );
      Console.WriteLine( "item5: " + item5.IsInstanceOfGenericType(typeof(Entity<>), false) );
      

      item: True
      item2: True
      item3: True
      item4: False
      item5: False
      

      【讨论】:

      • 出于好奇;使用反射在多大程度上影响性能?怎么会这样?另外,谢谢你的解决方案,我可以试试。
      【解决方案3】:

      您可以将变量的泛型类型定义与实体类的泛型类型定义进行比较。

      Type genericType = typeof(Entity<>);
      
      var a = new Entity<string>();
      
      bool isAOfTypeEntity =
          a.GetType().IsGenericType &&
          a.GetType().GetGenericTypeDefinition() == genericType;
      
      // returns true.
      

      注意,我们首先检查 IsGenericType,否则 GetGenericTypeDefinition 会抛出错误。

      还请先检查是否为空。我认为你可以将所有这些重构为一个方法。

      可能有更快或更好的方法,如果提供的话,我会很高兴看到它们。

      希望这会有所帮助。

      【讨论】:

      • 非常感谢!它现在工作得很好。
      【解决方案4】:

      这行得通:

      public class Entity<T>
      { 
      }
      
      static class Program
      {
          static void Main(string[] args)
          {
              var a = new Entity<string>();
              var b = new Entity<int>();
              var c = new Entity<Point>();
              var e = 1001;
              var f = new List<int>();
      
              if (a.IsEntity())
              {
                  Debug.WriteLine($"{nameof(a)} is an Entity");
              }
              if (b.IsEntity())
              {
                  Debug.WriteLine($"{nameof(b)} is an Entity");
              }
              if (c.IsEntity())
              {
                  Debug.WriteLine($"{nameof(c)} is an Entity");
              }
              if (e.IsEntity())
              {
                  Debug.WriteLine($"{nameof(e)} is an Entity");
              }
              if (f.IsEntity())
              {
                  Debug.WriteLine($"{nameof(f)} is an Entity");
              }
          }
      
          static bool IsEntity(this object obj)
          {
              var t = obj.GetType();
              if (t.IsGenericType)
              {
                  return typeof(Entity<>).IsAssignableFrom(t.GetGenericTypeDefinition());
              }
              return false;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2019-06-04
        • 2010-11-02
        • 1970-01-01
        • 1970-01-01
        • 2011-11-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-18
        相关资源
        最近更新 更多