如何确定对象的类型是否实现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
还是从Base
inheritance。
更新 :这是一些示例代码:
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。
希望这有助于某人。