如何确定对象的类型是否实现IEnumerable ,其中X使用Reflection从Base派生

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

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

如果o的类型实现IEnumerable任何接口,其中X派生自Base ,那么Test返回true,所以如果我这样做:

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

……使用Reflection可以做正确的事情。 我确定这是跨越所有类型接口的问题,找到符合要求的第一个,但我很难找到其中的通用IEnumerable

当然,我可以考虑这个:

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

……但是把它想象成一个思想实验。

您还可以使用看起来像这样的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; } } 

您可以使用Type.FindInterfaces过滤掉类型实现的所有IEnumerable<>接口,并检查每个接口上的generics参数(通过Type.GetGenericArguments )以查看它是Base还是从Baseinheritance。

更新 :这是一些示例代码:

 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 { } 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; } } } 

我最近编写了一些需要迭代任何集合的代码。

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

这是一个摘录:

 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。
它还捕获诸如List <>之类的通用集合,因为它们也是IEnumerable。

希望这有助于某人。