【问题标题】:How do I tell whether a Type implements IList<>?如何判断一个类型是否实现了 IList<>?
【发布时间】:2009-06-04 16:12:09
【问题描述】:

我想编写一个使用反射来判断给定类型是否实现IList&lt;T&gt; 的方法。例如:

IsGenericList(typeof(int))                       // should return false
IsGenericList(typeof(ArrayList))                 // should return false
IsGenericList(typeof(IList<int>))                // should return true
IsGenericList(typeof(List<int>))                 // should return true
IsGenericList(typeof(ObservableCollection<int>)) // should return true

在我的使用中,我可以假设该类型将始终是实例化的泛型类型(或根本不是泛型的东西)。

不幸的是,这并不像应该的那么容易。显而易见的解决方案:

public bool IsGenericList(Type type)
{
    return typeof(IList<>).IsAssignableFrom(type);
}

不起作用;它总是返回假。显然,像 IList&lt;&gt; 这样的非实例化泛型类型并没有像我期望的那样实现 IsAssignableFrom:IList&lt;&gt; 不能从 List&lt;T&gt; 分配。

我也试过这个:

public bool IsGenericList(Type type)
{
    if (!type.IsGenericType)
        return false;
    var genericTypeDefinition = type.GetGenericTypeDefinition();
    return typeof(List<>).IsAssignableFrom(genericTypeDefinition);
}

即,将 type 转换为其非实例化泛型,例如 IList&lt;int&gt; -> IList&lt;&gt;,然后再次尝试 IsAssignableFrom。当类型是实例化的IList&lt;T&gt;(例如IList&lt;int&gt;IList&lt;object&gt; 等)时,这将返回true。但是对于实现IList&lt;T&gt; 的类(例如List&lt;int&gt;ObservableCollection&lt;double&gt; 等),它返回false,所以显然IList&lt;&gt; 不能从 List&lt;&gt; 分配。再次,不是我所期望的。

如何编写 IsGenericList 并使其像上面的示例一样工作?

【问题讨论】:

    标签: .net generics reflection


    【解决方案1】:

    事实上,您不能拥有泛型类型定义的实例。因此,IsAssignableFrom() 方法按预期工作。要实现您想要的,请执行以下操作:

    public bool IsGenericList(Type type)
    {
        if (type == null) {
            throw new ArgumentNullException("type");
        }
        foreach (Type @interface in type.GetInterfaces()) {
            if (@interface.IsGenericType) {
                if (@interface.GetGenericTypeDefinition() == typeof(ICollection<>)) {
                    // if needed, you can also return the type used as generic argument
                    return true;
                }
            }
        }
        return false;
    }
    

    只是出于好奇,你需要这个做什么?

    【讨论】:

    • +1 - 这行得通,并且是目前唯一可行的解​​决方案 - 在我发布同样的内容后,我才意识到你有这个。
    • 很好的解决方案。 :) 小点但是:使用@ 符号通常是不推荐的做法。 (您可以只调用变量icurInterface 来解决名称冲突。)
    • 您缺少该方法的 { 并且您使用 ICollection 而不是 IList,但除此之外,这非常有效,谢谢!
    • 我在反射类型上的字段和属性并将它们重新设置回默认值(引用类型为 null)时使用了它。对于列表,我想将它们设置回空列表而不是 null。
    • 小心@JoeWhite,如果您将ICollection 替换为IList,那么IsGenericList(typeof(IList&lt;int&gt;)) 将返回False。修复以下stackoverflow.com/a/13589104/284795
    【解决方案2】:

    我也想测试一个类型是否为某些 T 实现 IList&lt;T&gt;。我对 Lucero's answer 进行了明显的更改,但它导致 subtle bug 在原始答案中不存在。这是我的最终编辑:

        /// <summary>
        /// Test if a type derives from IList of T, for any T.
        /// </summary>
        public bool TestIfGenericList(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }
    
            var interfaceTest = new Predicate<Type>(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>));
    
            return interfaceTest(type) || type.GetInterfaces().Any(i => interfaceTest(i));
        }
    

    【讨论】:

    • 谢谢,这确实比接受的答案更好,因为它适用于 IList&lt;T&gt; 本身。
    【解决方案3】:

    Lucero/Reed Copsey 现在都有正确的解决方案。为了更简洁,这里是 LINQified 形式:

    var isGenericList = type.GetInterfaces().Any(t => t.IsGenericType && 
        t.GetGenericTypeDefinition() == typeof(IList<>));
    

    【讨论】:

    • 不起作用,因为 GetInterfaces() 不会返回泛型类型定义,只会返回泛型类型(例如 IList)。
    • 是的,所以没有。我已经更新了它,但它现在似乎可以工作了。
    • 如果你愿意,你可以使用 Linq 重写我的解决方案...... ;)
    • 我没有选择 Linq,因为从问题中只能清楚地看到泛型可用,而不是使用什么版本的 C# 编译器。
    • 案例 #3 再次失败......看看我的解决方案 - 更短更快
    【解决方案4】:

    使用这个: http://msdn.microsoft.com/en-us/library/system.type.findinterfaces.aspx

    我试过了:

     public class Test : IList<string>
     {
    //implementation left out...
     }
    
    class Program
        {
            static void Main(string[] args)
            {
                Test t = new Test();
                TypeFilter myFilter = new TypeFilter(MyInterfaceFilter);
    
                Type type = t.GetType();
                Type[] x = type.FindInterfaces(myFilter, "System.Collections.Generic.IList");
                Console.WriteLine(x.Length);
    
            }
    
            public static bool MyInterfaceFilter(Type typeObj, Object criteriaObj)
            {
                if (typeObj.ToString().Contains(criteriaObj.ToString()))
                    return true;
                else
                    return false;
            }
        }
    

    【讨论】:

    • 使用非强名称来标识类型是非常不安全的。任何人都可以使用该名称创建类型,但这并不意味着它就是您要测试的类型。
    • 没错,你可以用这个替换它:Type[] x = type.FindInterfaces(myFilter, typeof(IList).FullName);
    【解决方案5】:

    这通过了你的测试......

    public static bool IsGenericList( Type type )
    {
      return type.Name == "IList`1" || type.GetInterface( "IList`1" ) != null;
    }
    

    【讨论】:

    • type 不必是泛型来实现泛型接口。你可以有这个:class IntList: object, IList { .... } 这不会使 IntList 泛型。
    • 根本不需要 IsGeneric 检查
    【解决方案6】:

    我喜欢Colonel Panic's answer,但我决定让答案更通用一点,这样我就可以在其他场景中重复使用它:

        public static bool InstanceOfGenericType(this Type self, Type genericType)
        {
            return self.IsGenericType && self.GetGenericTypeDefinition() == genericType;
        }
    
        public static bool InstanceOfGenericInterface(this Type self, Type ifaceType)
        {
            return self.InstanceOfGenericType(ifaceType) 
                || self.GetInterfaces().Any(i => i.InstanceOfGenericType(ifaceType));
        }
    
        public static bool IsIList(this Type t)
        {
            return t.InstanceOfGenericInterface(typeof(IList<>));
        }
    

    【讨论】:

      【解决方案7】:

      你试过打电话给Type.GetInterface()吗?从帮助中并不完全清楚,但我认为它会搜索由基类型实现的接口,除了类型本身。如果没有,您可以随时循环访问Type.BaseType 并再次调用GetInterface()

      【讨论】:

      • GetInterface 仅在您知道特定的通用参数时才有效,但不适用于 IList
      【解决方案8】:

      使用“is”运算符:

      is 运算符用于检查 对象的运行时类型是否 与给定类型兼容。

      【讨论】:

      • 我没有实例。我有类型。
      • 这不适用于 IList,仅适用于 IList 等。您需要有一个具体类型才能使“is”工作...
      • 您需要is 的实例。 OP 询问如何使用Type 进行检查。
      猜你喜欢
      • 1970-01-01
      • 2012-06-07
      • 2012-02-11
      • 2019-08-03
      • 2014-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多