Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have a bunch of IEnumerable Collections which exact number and types is subject of 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 it's count without having to rewrite the code after every code generation. So i am looking for a generic approach using reflection. The result i am looking for is something like:

MyType: 23
OtherType: 42

My problem is that i can't figure how to invoke the Count method properly. Here is what i have so far:

        // 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);
                }
            }
        }
like image 550
mbi Avatar asked Aug 23 '10 09:08

mbi


People also ask

How do you get the count of an IEnumerable?

Simplifying all answer. IEnumerable has not Count function or property. To get this, you can store count variable (with foreach, for example) or solve using Linq to get count. Save this answer.

What does count () do in C#?

To count the number of elements in the C# array, we can use the count() method from the IEnumerable. It is included in the System.

What is Linq enumerable?

The most basic enumerable is an array, which can store a fixed number of typed elements. int[] numbers = new int[3] { 1, 2, 3}; In the example above, we create an integer array that can hold 3 values and initialize the array with the values 1, 2 and 3.

How do you measure length of IEnumerable?

If you need to read the number of items in an IEnumerable<T> you have to call the extension method Count , which in general (look at Matthew comment) would internally iterate through the elements of the sequence and it will return you the number of items in the sequence. There isn't any other more immediate way.


1 Answers

If you insist on doing it the hard way ;p

Changes:

  • how you obtain countMethodInfo for a generic method
  • the arguments to Invoke

Code (note obj 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);
            }
        }
    }
like image 107
Marc Gravell Avatar answered Sep 21 '22 14:09

Marc Gravell