【问题标题】:Finding out if a type implements a generic interface找出一个类型是否实现了一个泛型接口
【发布时间】:2010-11-10 10:42:41
【问题描述】:

假设我有一个类型,MyType。我想做以下事情:

  1. 找出 MyType 是否为某些 T 实现 IList 接口。
  2. 如果 (1) 的答案是肯定的,请找出 T 是什么。

执行此操作的方法似乎是 GetInterface(),但它只允许您按特定名称进行搜索。有没有办法搜索“所有形式为 IList 的接口”(如果接口是 IList 的子接口,如果可能,它也会很有用。)

相关:How to determine if a type implements a specific generic interface type

【问题讨论】:

    标签: c# .net reflection


    【解决方案1】:
    // this conditional is necessary if myType can be an interface,
    // because an interface doesn't implement itself: for example,
    // typeof (IList<int>).GetInterfaces () does not contain IList<int>!
    if (myType.IsInterface && myType.IsGenericType && 
        myType.GetGenericTypeDefinition () == typeof (IList<>))
        return myType.GetGenericArguments ()[0] ;
    
    foreach (var i in myType.GetInterfaces ())
        if (i.IsGenericType && i.GetGenericTypeDefinition () == typeof (IList<>))
            return i.GetGenericArguments ()[0] ;
    

    编辑: 即使myType 实现IDerivedFromList&lt;&gt; 但不是直接实现IList&lt;&gt;,IList&lt;&gt; 也会出现在GetInterfaces() 返回的数组中。

    更新:添加了对myType 是有问题的通用接口的边缘情况的检查。

    【讨论】:

    • 这也处理了数组的情况,这很好。如果要显式测试数组,请使用“if (myType.IsArray) return myType.GetElementType();” (虽然这可能会更快,但我希望这些都不是性能关键!)
    • 对于像我这样对为什么需要 .IsInterface 感到好奇的人:GetGenericTypeDefinition() 如果在非泛型类型上调用,则会抛出异常。
    • Type.IsGenericType 属性在 netstandard 1.6 及更低版本上不可用(因此在 .NET Core 1.0 上不可用),但您可以改用 TypeInfo.IsGenericType:type.GetTypeInfo().IsGenericType。
    • 如果 MyType 是开放基因类型怎么办?您还需要调用 GetGenericTypeDefinitiin 吗?换句话说,为什么 typeof(Dictionary).GetInterfaces().Contains(typeof(IDictionary)) 返回 false?
    • 因为你不能实现一个开放的通用接口。 Dictionary&lt;,&gt; 实现了IDictionary&lt;`0, `1&gt;,其中'0 和'1 指的是Dictionary&lt;,&gt; 的类型参数——在ILDasm 或类似中查找。
    【解决方案2】:

    使用反射(和一些 LINQ),您可以轻松做到这一点:

    public static IEnumerable<Type> GetIListTypeParameters(Type type)
    {
        // Query.
        return
            from interfaceType in type.GetInterfaces()
            where interfaceType.IsGenericType
            let baseInterface = interfaceType.GetGenericTypeDefinition()
            where baseInterface == typeof(IList<>)
            select interfaceType.GetGenericArguments().First();
    }
    

    首先,您将获取类型上的接口并仅过滤掉泛型类型的接口。

    然后,获取这些接口类型的泛型类型定义,看看它是否与IList&lt;&gt; 相同。

    从那里,获取原始接口的通用参数是一件简单的事情。

    请记住,一个类型可以有多个 IList&lt;T&gt; 实现,这就是返回 IEnumerable&lt;Type&gt; 的原因。

    【讨论】:

    • 如果将返回表达式用括号括起来并在末尾添加另一个“.First()”,那么它会返回一个 Type 而不是一个长度为 1 的 IEnumerable,这更容易一些处理。 (我个人认为这是对 LINQ 过于聪明的一个例子,但也许这就是我。)
    • @yoyo 或者,您可以在此方法的结果上调用First。如果你从这个方法返回First,你假设一个类型参数是完全错误的。
    • 好点@casperOne,OP 的 MyType 可以实现 IList 和 IList。所以问题应该是“找到T”而不是“找到T”。接受的答案也没有解决这个问题。
    【解决方案3】:
        public static bool Implements<I>(this Type type) where I : class
        {
             if (!typeof(I).IsInterface)
             {
                 throw new ArgumentException("Only interfaces can be 'implemented'.");
             }
    
             return typeof(I).IsAssignableFrom(type);
        }
    

    【讨论】:

      【解决方案4】:

      使用 Anton Tykhyy 的提议,这里有一个小的扩展方法来检查某些类型是否实现了具有给定泛型类型参数的泛型接口:

      public static class ExtensionMethods
      {
          /// <summary>
          /// Checks if a type has a generic interface. 
          /// For example 
          ///     mytype.HasGenericInterface(typeof(IList<>), typeof(int)) 
          /// will return TRUE if mytype implements IList<int>
          /// </summary>
          public static bool HasGenericInterface(this Type type, Type interf, Type typeparameter)
          {
              foreach (Type i in type.GetInterfaces())
                  if (i.IsGenericType && i.GetGenericTypeDefinition() == interf)
                      if (i.GetGenericArguments()[0] == typeparameter)
                          return true;
      
              return false;
          }
      }
      

      【讨论】:

        【解决方案5】:

        作为辅助方法扩展

        public static bool Implements<I>(this Type type, I @interface) where I : class  
        {
            if(((@interface as Type)==null) || !(@interface as Type).IsInterface)
                throw new ArgumentException("Only interfaces can be 'implemented'.");
        
            return (@interface as Type).IsAssignableFrom(type);
        }
        

        示例用法:

        var testObject = new Dictionary<int, object>();
        result = testObject.GetType().Implements(typeof(IDictionary<int, object>)); // true!
        

        【讨论】:

          【解决方案6】:
          Type[] typeArray2 = c.GetInterfaces();
          for (int num2 = 0; num2 < typeArray2.Length; num2++)
          {
               if (this == typeArray2[num2])
               {
                    return true;
               }
          }
          

          --http://www.hanselman.com/blog/DoesATypeImplementAnInterface.aspx

          【讨论】:

            【解决方案7】:

            如果我正确理解您的问题,这就是您想要做的。如果不是,请进一步解释。

            public class MyType : ISomeInterface
            {
            }
            
            MyType o = new MyType();
            
            if(o is ISomeInterface)
             {
             }
            

            编辑:如果您更改问题,请添加您编辑的事实。因为现在我的答案看起来不属于它。

            在这种情况下,这是一个非常大的 LINQ

                        var item = typeof(MyType).GetInterfaces()
                                        .Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IList<>))
                                        .Select(t => t.GetGenericArguments().First())
                                        .FirstOrDefault();
            
            if( item != null )
             //it has a type
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-06-09
              • 1970-01-01
              • 2011-02-01
              • 2010-10-04
              • 1970-01-01
              • 1970-01-01
              • 2020-12-17
              相关资源
              最近更新 更多