确定对象是否派生自集合类型

我想确定通用对象类型(“T”)方法类型参数是否是集合类型。 我通常会将T through作为Generic.List发送,但它可以是任何集合类型,因为它在辅助函数中使用。

我是否最好测试它是否实现IEnumerable ?

如果是这样,代码会是什么样子?

更新格林威治标准时间14:17 + 10可能在这里扩展一个解决方案(但是如果列表派生的话,它只适用于List 而不是IEnumerable )

T currentObj; // works if currentObj is List currentObj.GetType().GetGenericTypeDefinition() == typeof(List) // does not work if currentObj is List currentObj.GetType().GetGenericTypeDefinition() == typeof(IEnumerable) 

这将是最简单的检查..

 if(Obj is ICollection) { //Derived from ICollection } else { //Not Derived from ICollection } 

您可以将Type.GetInterface()与受损名称一起使用。

 private bool IsTAnEnumerable(T x) { return null != typeof(T).GetInterface("IEnumerable`1"); } 

为了在运行时获取T的实际类型,可以使用typeof(T)表达式。 从那里,普通类型比较运算符将起到作用

 bool isEnumerable = typeof(IEnumerable).IsAssignableFrom(typeof(T)); 

完整代码示例:

 static bool Foo() { return typeof(IEnumerable).IsAssignableFrom(typeof(T)); } Foo>(); // true Foo(); // false 

我个人倾向于使用自己编写的方法,名为TryGetInterfaceGenericParameters ,我在下面发布。 以下是如何在您的情况下使用它:

使用示例

 object currentObj = ...; // get the object Type[] typeArguments; if (currentObj.GetType().TryGetInterfaceGenericParameters(typeof(IEnumerable<>), out typeArguments)) { var innerType = typeArguments[0]; // currentObj implements IEnumerable } else { // The type does not implement IEnumerable for any T } 

这里需要注意的是,传入typeof(IEnumerable<>)而不是 typeof(IEnumerable) (这是一个完全不同的类型), 也不是任何T typeof(IEnumerable) (如果你已经知道了T ,你不需要这种方法)。 当然,这适用于任何通用接口,例如,您也可以使用typeof(IDictionary<,>) (但不能使用 typeof(IDictionary) )。

方法来源

 ///  /// Determines whether the current type is or implements the specified generic interface, and determines that /// interface's generic type parameters. ///  /// The current type. ///  /// A generic type definition for an interface, eg typeof(ICollection<>) or typeof(IDictionary<,>). ///  /// Will receive an array containing the generic type parameters of the interface. ///  /// True if the current type is or implements the specified generic interface. public static bool TryGetInterfaceGenericParameters(this Type type, Type @interface, out Type[] typeParameters) { typeParameters = null; if (type.IsGenericType && type.GetGenericTypeDefinition() == @interface) { typeParameters = type.GetGenericArguments(); return true; } var implements = type.FindInterfaces((ty, obj) => ty.IsGenericType && ty.GetGenericTypeDefinition() == @interface, null).FirstOrDefault(); if (implements == null) return false; typeParameters = implements.GetGenericArguments(); return true; } 

另外,请记住,因为您使用generics,不要忘记其他基本技术,在这种情况下,如重载。 我怀疑你是在计划这样的事情:

 void SomeFunc(T t) { if (IsCollectionCase(t)) DoSomethingForCollections() else DoSOmethingElse(); } 

这将更好地处理如下:

 void SomeFunc(IEnumerable t) { DoSomethingForCollections() } void SomeFunc(T t) { DoSomethingElse() } 

我会测试IEnumerable ,因为集合类型只能实现IEnumerable ,它不必实现IEnumerable

它还取决于:你对收集类型的意思是什么? 您可以拥有一个集合,而无需实现任何这些接口。

虽然我不能确定原始海报的意图是什么,但是对于IEnumerable进行测试的铸造效果已经有了几个回应。 这很好,但是每个人都应该知道字符串实例通过了这个测试,这可能不是原作者想要的。 我知道当我去寻找答案并发现这篇文章时我当然没有:

 string testString = "Test"; Console.WriteLine(testString as IEnumerable != null); // returns true 

我正在尝试编写一个使用reflection来完成某些任务的自定义序列化程序。 作为任务的一部分,我需要确定属性值是项的集合/数组/列表还是单个属性值。 特别令人讨厌的是,几个Linq表达式实际上导致了一个可枚举的类型值,但GetType()。IsArray为这些返回false,并将它们转换为ICollection也返回null,但是将它们转换为IEnumerable会返回一个非null值。

所以……目前,我仍然在寻求一种适用于所有情况的解决方案。

为简单起见和代码共享,我通常使用此扩展方法:

 public static bool IsGenericList(this object obj) { return IsGenericList(obj.GetType()); } public static bool IsGenericList(this 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 (type.GetInterface("IEnumerable") != null); } 

尝试将任何对象序列化为JSON格式时,我遇到了同样的问题。 以下是我最终使用的内容:

 Type typ = value.GetType(); // Check for array type if(typeof(IEnumerable).IsAssignableFrom(typ) || typeof(IEnumerable<>).IsAssignableFrom(typ)) { List list = ((IEnumerable)value).Cast().ToList(); //Serialize as an array with each item in the list... } else { //Serialize as object or value type... } 

我喜欢generics。 在这个方法中, T必须有一个public和无参数构造函数,这意味着你不能将IList用于T 您必须使用List

 public static T IsEnumerable() where T : new() { if (new T() is IEnumerable) { }