Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I enumerate through an object of type `T` when it is a IEnumerable

Tags:

c#

reflection

This is a bit difficult to explain. So here it goes.

I have a function like this:

public T FooBar<T>(Func<T> function)
{
   T returnData = function();

   // want to iterate through returnData to do something to it

   return returnData;
}

If the returnData (T) is an IEnumerable list, then I would like to enumerate through returnData to modify its contents using reflection. But I can't seem to be able to do it. When I try to cast returnData to an enumerable type, I get an exception:

Unable to cast object of type

'System.Collections.Generic.List`1[Cars]'

to type

'System.Collections.Generic.List`1[System.Object]'.

I will not know that the return type will be a list of 'cars' for example ahead of time, only at run time. So I have to check using reflection if it is a list, and then try to cast it so that I can enumerate through it.

Unless I am going about it the wrong way. How can I enumerate through returnData if it is of type T?

like image 594
7wp Avatar asked Jun 13 '11 23:06

7wp


People also ask

What is possible multiple enumeration of IEnumerable?

Deferred Danger One of the many useful warnings in ReSharper is “Possible multiple enumeration of IEnumerable“. If you enumerate an enumerable more than once, ReSharper detects that and warns you about it. Although this warning may seem pointless at first, there are two good reasons to pay attention to it.

What is IEnumerable T?

IEnumerable. IEnumerable<T> contains a single method that you must implement when implementing this interface; GetEnumerator, which returns an IEnumerator<T> object. The returned IEnumerator<T> provides the ability to iterate through the collection by exposing a Current property.

What is IEnumerable <> in C#?

IEnumerable is an interface defining a single method GetEnumerator() that returns an IEnumerator interface. It is the base interface for all non-generic collections that can be enumerated. This works for read-only access to a collection that implements that IEnumerable can be used with a foreach statement.


2 Answers

One approach is to add a type constraint on T, but this is not ideal:

public T FooBar<T>(Func<T> function) where T : IEnumerable
{
    // T is not strongly typed for the enumerated item

If you changed your method slightly (w.r.t. T):

public IEnumerable<T> FooBar<T>(Func<IEnumerable<T>> function)

Then you have strong typing on the actual item being enumerated with the added bonus of accepting enumerable objects.


So I noticed from a second read of your question, there is some confusion about what T means for your variable returnData. In the case where FooBar() is passed a List<Car>, T is List<Car>, and really has no association with the generic type specification of the List<> itself. You can think of it as some List<U> where U is some other, unknown type.

At runtime you will have no simple way to get to U as it is hidden, so to speak, inside T. You could use overloading as some of the other answerers recommend, and provide a non-IEnumerable<U> method and one which takes arguments of type Func<IEnumerable<T>>.

Perhaps with some more details about the goal of FooBar<T> we could make some more specific recommendations.

like image 174
user7116 Avatar answered Sep 29 '22 23:09

user7116


if (returnData is System.Collections.IEnumerable)
{
   foreach (object o in (System.Collections.IEnumerable)returnData)
   {
      // Do something.
   }
}

Really, though, why not have an additional overload like this:

public T FooBar<T>(Func<IEnumerable<T>> function) 
like image 29
agent-j Avatar answered Sep 30 '22 01:09

agent-j