我有一堆IEnumerable集合,确切的数量和类型经常更改(由于自动代码生成)。
它看起来像这样:
public class MyCollections {
public System.Collections.Generic.IEnumerable<SomeType> SomeTypeCollection;
public System.Collections.Generic.IEnumerable<OtherType> OtherTypeCollection;
...
在运行时,我想确定每个Type及其计数,而不必在每次代码生成后重写代码。所以我正在寻找使用反射的通用方法。我正在寻找的结果是:
MyType: 23
OtherType: 42
我的问题是我无法想象如何正确调用Count方法。以下是我到目前为止的情况:
// Handle to the Count method of System.Linq.Enumerable
MethodInfo countMethodInfo = typeof(System.Linq.Enumerable).GetMethod("Count", new Type[] { typeof(IEnumerable<>) });
PropertyInfo[] properties = typeof(MyCollections).GetProperties();
foreach (PropertyInfo property in properties)
{
Type propertyType = property.PropertyType;
if (propertyType.IsGenericType)
{
Type genericType = propertyType.GetGenericTypeDefinition();
if (genericType == typeof(IEnumerable<>))
{
// access the collection property
object collection = property.GetValue(someInstanceOfMyCollections, null);
// access the type of the generic collection
Type genericArgument = propertyType.GetGenericArguments()[0];
// make a generic method call for System.Linq.Enumerable.Count<> for the type of this collection
MethodInfo localCountMethodInfo = countMethodInfo.MakeGenericMethod(genericArgument);
// invoke Count method (this fails)
object count = localCountMethodInfo.Invoke(collection, null);
System.Diagnostics.Debug.WriteLine("{0}: {1}", genericArgument.Name, count);
}
}
}
答案 0 :(得分:3)
这将涉及一些MakeGenericMethod
- 并且很多反射通常。就个人而言,在这种情况下,我很想通过抛弃泛型来简化:
public static int Count(IEnumerable data) {
ICollection list = data as ICollection;
if(list != null) return list.Count;
int count = 0;
IEnumerator iter = data.GetEnumerator();
using(iter as IDisposable) {
while(iter.MoveNext()) count++;
}
return count;
}
即使通过反射获取,也可以轻易地转换为非泛型IEnumerable
。
答案 1 :(得分:3)
如果你坚持不懈地去做; p
的变化:
代码(注意obj
是我MyCollections
}的实例:
MethodInfo countMethodInfo = typeof (System.Linq.Enumerable).GetMethods().Single(
method => method.Name == "Count" && method.IsStatic && method.GetParameters().Length == 1);
PropertyInfo[] properties = typeof(MyCollections).GetProperties();
foreach (PropertyInfo property in properties)
{
Type propertyType = property.PropertyType;
if (propertyType.IsGenericType)
{
Type genericType = propertyType.GetGenericTypeDefinition();
if (genericType == typeof(IEnumerable<>))
{
// access the collection property
object collection = property.GetValue(obj, null);
// access the type of the generic collection
Type genericArgument = propertyType.GetGenericArguments()[0];
// make a generic method call for System.Linq.Enumerable.Count<> for the type of this collection
MethodInfo localCountMethodInfo = countMethodInfo.MakeGenericMethod(genericArgument);
// invoke Count method (this fails)
object count = localCountMethodInfo.Invoke(null, new object[] {collection});
System.Diagnostics.Debug.WriteLine("{0}: {1}", genericArgument.Name, count);
}
}
}
答案 2 :(得分:2)
到现在为止,这个问题已经得到了回答,但是我想向你们展示一个“调用通用扩展方法”的修剪版 - 我认为相当简单的版本,可以用来反思地调用Count
:
// get Enumerable (which holds the extension methods)
Type enumerableT = typeof(Enumerable);
// get the Count-method (there are only two, you can check the parameter-count as in above
// to be certain. Here we know it's the first, so I use the first:
MemberInfo member = enumerableT.GetMember("Count")[0];
// create the generic method (instead of int, replace with typeof(yourtype) in your code)
MethodInfo method = ((MethodInfo) member).MakeGenericMethod(typeof(int));
// invoke now becomes trivial
int count = (int)method.Invoke(null, new object[] { yourcollection });
以上是有效的,因为您不需要使用IEnumerable<>
的泛型类型来调用Count
,这是Enumerable
的扩展并且需要参数IEnumerable<T>
作为第一个参数(它是一个扩展名),但您不需要指定它。
请注意,从您的问题的阅读中,在我看来,您实际上应该为您的类型使用泛型,这会将类型安全性添加回您的项目中,并且仍允许您使用Count或其他任何内容。毕竟,有一件事是肯定的,都是Enumerable
,对吧?如果是这样,谁需要反思?
答案 3 :(得分:1)
var count = System.Linq.Enumerable.Count(theCollection);
编辑:你说它是生成的,所以你不能仅通过调用Count()
来生成属性吗?
public class MyCollections
{
public System.Collections.Generic.IEnumerable<SomeType> SomeTypeCollection;
public System.Collections.Generic.IEnumerable<OtherType> OtherTypeCollection;
public int CountSomeTypeCollection
{
get { return this.SomeTypeCollection.Count(); }
}
...