How to call System.Linq.Enumerable.Count <> on IEnumerable <T> using Reflection?

I have a bunch of IEnumerable Collections in which the exact number and types are subject to frequent changes (due to automatic code generation).

It looks something like this:

 public class MyCollections { public System.Collections.Generic.IEnumerable<SomeType> SomeTypeCollection; public System.Collections.Generic.IEnumerable<OtherType> OtherTypeCollection; ... 

At runtime, I want to determine each type and its quantity without rewriting the code after each code generation. Therefore, I am looking for a general approach using reflection. The result I'm looking for is something like:

 MyType: 23 OtherType: 42 

My problem is that I cannot figure out how to properly call the Count method. Here is what I still have:

  // 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); } } } 
+6
source share
4 answers

If you insist on doing it the hard way, p

Changes:

  • how do you get countMethodInfo for a generic method
  • arguments to call

Code ( obj note is my instance of 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); } } } 
+3
source

This will include some MakeGenericMethod - and a lot of reflection in general. Personally, I would have a desire to simply simplify it by discarding generics in this case:

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

You can distinguish non-standard IEnumerable trivially, even if the selection is through reflection.

+2
source
 var count = System.Linq.Enumerable.Count(theCollection); 

Edit: you say this is generated, so you can not just generate properties with calls to 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(); } } ... 
+1
source

This question has been answered, but I would like to present you a cropped picture; and I think the rather trivial version is the "call of the general extension method", which can be used to reflect Count reflectively:

 // 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 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 }); 

This works because you do not need to use the generic IEnumerable<> type to call Count , which is an Enumerable extension and accepts the IEnumerable<T> argument as the first parameter (this is an extension), but you do not need to specify this.

Please note that from reading your question, it seems to me that you should use generics for your types, which adds type safety to your project and allows you to use Count or something else. After all, the only thing that is certain is that everything is Enumerable , right? If so, who needs reflection?

+1
source

All Articles