【问题标题】:Infer Generic Type of Interface推断接口的通用类型
【发布时间】:2014-05-20 01:25:51
【问题描述】:

-- 上下文

我有以下 5 个对象

IChangeStatus<T>
myFirstClass : IChangeStatus<firstClassEnum>
mySecondClass : IChangeStatus<secondClassEnum>

myClassHandler<TEntity>
myFirstClassHandler : myClassHandler<myFirstClass>

出于问题的目的,我们可以假设接口只有属性

T Status { get; }

-- 问题

1.- 如果 TEntity 的实例实现 IChangeStatus,我如何在 myClassHandler 的方法中询问?

2.- 我如何迭代 TEntity 的 IEnumerable,假设它们具有特定的 IChangeStatus?

【问题讨论】:

  • 关于问题 #1 - 您是否正在寻找一种在运行时检查 TEntity 实现 IChangeStatus 的方法,还是在编译时确保 TEntity 始终为 IChangeStatus 类型的方法?
  • 我刚刚看到这个评论,我正在寻找运行时检查,我已经在另一个 SO 问题中找到了它,在我的答案中。

标签: c# .net generics interface


【解决方案1】:

我找到了另一个SO Question - Check if a type implements a generic interface without considering the generic type arguments,它给了我一个更通用的答案,这正是我正在寻找的:

return entity.GetType().GetInterfaces()
       .Where(i => i.IsGenericType)
       .Any(i => i.GetGenericTypeDefinition() == typeof(IChangeStatus<>));

至于假设 IChangeStatus 的特定类型对 IEnumerable 的迭代,因为我们指出了该类型确实实现了接口,因此具有 Status 属性...所以我选择了 dynamic 类型。

【讨论】:

    【解决方案2】:

    如果您想在MyClassHandler 中使用IChangeStatus&lt;T&gt; 中的T,则必须添加另一个类型参数。例如:

    class MyClassHandler<TEntity, TStatus>
        where TEntity : IChangeStatus<TStatus>
    {
         public IEnumerable<TStatus> Statuses
         {
              get { return _entities.Select(entity => entity.Status); }
         }
    }
    

    where 子句将确保实体和状态类型相互关联。

    如果您不想这样做,您可以添加一个额外的非泛型接口,该接口公开Status 类型的Object 属性。这样会丢失一些静态类型,但不需要额外的类型参数。

    【讨论】:

      【解决方案3】:

      要检查您的类是否实现了 IChangeStatus,您只需执行以下操作:

      public void FooMethod(ClassType myClass)
      {
        var doesImplementIChange = myClass as IChangeStatus<SomeClass>
        if (doesImplementIChange != null)
        {
          // Do stuff..
        }
      }
      

      要遍历您的类的 IEnumerable:

      foreach (var data in myClass.OfType<MyType>())
              {
                  // Do stuff..
              }
      

      或者,你可以这样做:

      foreach (var cls in myClass)
              {
                  var myCls = myClass as IChangeStatus<SomeClass>;
                  if (myCls != null)
                  {
                      // Do stuff..
                  }
              }
      

      【讨论】:

      • 这是我实现它的方式,但是我不喜欢 ifs 列表...我想也许有更好的解决方案。
      • 至于检查 id 是否实现了接口,除了强制类型转换和空值检查之外别无他法。但是对于 foreach 语句,您可以使用第一个选项,您不会有任何 if 语句
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-24
      • 2019-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多