How do I define an Extension Method for IEnumerable<T>
which returns IEnumerable<T>
?
The goal is to make the Extension Method available for all IEnumerable
and IEnumerable<T>
where T
can be an anonymous type.
The easiest way to write any iterator is with an iterator block, for example:
static IEnumerable<T> Where<T>(this IEnumerable<T> data, Func<T, bool> predicate)
{
foreach(T value in data)
{
if(predicate(value)) yield return value;
}
}
The key here is the "yield return
", which turns the method into an iterator block, with the compiler generating an enumerator (IEnumerator<T>
) that does the same. When called, generic type inference handles the T
automatically, so you just need:
int[] data = {1,2,3,4,5};
var odd = data.Where(i=>i%2 != 0);
The above can be used with anonymous types just fine.
You can, of coure, specify the T
if you want (as long as it isn't anonymous):
var odd = data.Where<int>(i=>i%2 != 0);
Re IEnumerable
(non-generic), well, the simplest approach is for the caller to use .Cast<T>(...)
or .OfType<T>(...)
to get an IEnumerable<T>
first. You can pass in this IEnumerable
in the above, but the caller will have to specify T
themselves, rather than having the compiler infer it. You can't use this with T
being an anonymous type, so the moral here is: don't use the non-generic form of IEnumerable
with anonymous types.
There are some slightly more complex scenarios where the method signature is such that the compiler can't identify the T
(and of course you can't specify it for anonymous types). In those cases, it is usually possible to re-factor into a different signature that the compiler can use with inference (perhaps via a pass-thru method), but you'd need to post actual code to provide an answer here.
(updated)
Following discussion, here's a way to leverage Cast<T>
with anonymous types. The key is to provide an argument that can be used for the type inference (even if the argument is never used). For example:
static void Main()
{
IEnumerable data = new[] { new { Foo = "abc" }, new { Foo = "def" }, new { Foo = "ghi" } };
var typed = data.Cast(() => new { Foo = "never used" });
foreach (var item in typed)
{
Console.WriteLine(item.Foo);
}
}
// note that the template is not used, and we never need to pass one in...
public static IEnumerable<T> Cast<T>(this IEnumerable source, Func<T> template)
{
return Enumerable.Cast<T>(source);
}