代码之家  ›  专栏  ›  技术社区  ›  Dave Van den Eynde

如何确定对象的类型是否实现IEnumerable<x>其中x是使用反射从基派生的

  •  5
  • Dave Van den Eynde  · 技术社区  · 15 年前

    给出一个基类 Base ,我想编写一个方法测试,如下所示:

    private static bool Test(IEnumerable enumerable)
    {
    ...
    }
    

    如果o类型实现了 IEnumerable<X> 在哪里? X 来源 基地 如果我这样做:

    public static IEnumerable<string> Convert(IEnumerable enumerable)
    {
        if (Test(enumerable))
        {
            return enumerable.Cast<Base>().Select(b => b.SomePropertyThatIsString);
        }
    
        return enumerable.Cast<object>().Select(o => o.ToString());
    }
    

    …用反射来做正确的事情。我敢肯定,遍历类型的所有接口以找到符合需求的第一个接口是很困难的,但是我很难找到通用的 IEnumerable<> 其中。

    当然,我可以考虑:

    public static IEnumerable<string> Convert(IEnumerable enumerable)
    {
        return enumerable.Cast<object>().Select(o => o is Base ? ((Base)o).SomePropertyThatIsString : o.ToString());
    }
    

    …但把它当作思维实验。

    3 回复  |  直到 11 年前
        1
  •  16
  •   VoidDweller    15 年前

    您也可以使用 LINQ 看起来像这样的查询。

    public static bool ImplementsBaseType(IEnumerable objects)
    {
        int found = ( from i in objects.GetType().GetInterfaces()
                     where i.IsGenericType && 
                           i.GetGenericTypeDefinition() == typeof(IEnumerable<>) &&
                           typeof(MyBaseClass).IsAssignableFrom(i.GetGenericArguments()[0])
                     select i ).Count();
    
        return (found > 0);
    }
    

    此代码采用以下using语句:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    

    因为这只是一个思想实验。这里是作为扩展方法的另一个实现。

    public static class ConversionAssistants
    {
        public static bool GenericImplementsType(this IEnumerable objects, Type baseType)
        {
            foreach (Type type in objects.GetType().GetInterfaces())
            {
                if (type.IsGenericType)
                {
                    if (type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
                    {
                        if (baseType.IsAssignableFrom(type.GetGenericArguments()[0]))
                            return true;
                    }
                }
            }
            return false;
        }
    }
    
        2
  •  0
  •   Franci Penov    15 年前

    你可以使用 Type.FindInterfaces 过滤掉所有 IEnumerable<> 接口类型实现并检查通用参数(通过 Type.GetGenericArguments )在他们每个人身上看看 Base 或继承自 基地 .

    更新 :下面是一些示例代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Reflection;
    
    namespace ConsoleApplication1
    {
        class Base
        {
            string Prop { get; set;}
        }
    
        class A : Base
        {
        }
    
        class Test : List<A>
        {
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    Test test = new Test();
                    Type myType = test.GetType();
    
                    //string filterCriteria = "IEnumerable`1";
                    Type typeA = Type.GetType("ConsoleApplication1.A");
                    string filterCriteria = "System.Collections.Generic.IEnumerable`1[[" +
                                            typeA.AssemblyQualifiedName +
                                            "]]";
    
                    // Specify the TypeFilter delegate that compares the 
                    // interfaces against filter criteria.
                    TypeFilter myFilter = new TypeFilter(MyInterfaceFilter);
                    Type[] myInterfaces = myType.FindInterfaces(myFilter,
                        filterCriteria);
                    if (myInterfaces.Length > 0)
                    {
                        Console.WriteLine("\n{0} implements the interface {1}.",
                            myType, filterCriteria);
                        for (int j = 0; j < myInterfaces.Length; j++)
                            Console.WriteLine("Interfaces supported: {0}.",
                                myInterfaces[j].ToString());
                    }
                    else
                        Console.WriteLine(
                            "\n{0} does not implement the interface {1}.",
                            myType, filterCriteria);
                }
                catch (ArgumentNullException e)
                {
                    Console.WriteLine("ArgumentNullException: " + e.Message);
                }
                catch (TargetInvocationException e)
                {
                    Console.WriteLine("TargetInvocationException: " + e.Message);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Exception: " + e.Message);
                }
            }
    
            public static bool MyInterfaceFilter(Type typeObj, Object criteriaObj)
            {
                // This will be true, if criteria is
                // System.Collections.Generic.IEnumerable`1[[ConsoleApplication1.A, ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
                if (typeObj.FullName == criteriaObj.ToString())
                    return true;
                // This will be true, if criteria is
                // IEnumerable`1
                // You will still need to check the generic parameters on the original type
                    // (generic parameters are not exposed on Type instances for interfaces
                else if (typeObj.Name == criteriaObj.ToString())
                    return true;
                else
                    return false;
            }
        }
    }
    
        3
  •  -2
  •   Simon Miller    11 年前

    我最近编写了一些代码,需要对任何集合进行迭代。

    作为一个传统的.NET应用程序,我甚至没有可用的泛型!

    以下是摘录:

    var t = objects.GetType(); // to be compatible with the question
    
    bool isIEnumerable = false;
    foreach (var i in t.GetInterfaces())
    {
        if (i == typeof(IEnumerable))
        {
            isIEnumerable = true;
            break;
        }
    }
    

    我发现甚至.NET 1.1集合类(如sqlparameterCollection)都是IEnumerable。
    它还捕获通用集合,如列表<gt;,因为这些集合也是IEnumerable。

    希望这能帮助别人。