views:

2023

answers:

3

Hi,

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.

Kind regards.

A: 

This post may help you to get started:http://stackoverflow.com/questions/68750/how-do-you-write-a-c-extension-method-for-a-generically-typed-class#68772. I'm not sure if it is exactly what you are looking for but it might get you started.

Nathan W
+7  A: 

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);
}
Marc Gravell
A method with a parameter that isn't used just seems wrong.
Cameron MacFarland
It *is* used.... just by the compiler, not the runtime ;-
Marc Gravell
A: 
using System;
using System.Collections.Generic;

namespace ExtentionTest {
    class Program {
        static void Main(string[] args) {

            List<int> BigList = new List<int>() { 1,2,3,4,5,11,12,13,14,15};
            IEnumerable<int> Smalllist = BigList.MyMethod();
            foreach (int v in Smalllist) {
                Console.WriteLine(v);
            }
        }

    }

    static class EnumExtentions {
        public static IEnumerable<T> MyMethod<T>(this IEnumerable<T> Container) {
            int Count = 1;
            foreach (T Element in Container) {
                if ((Count++ % 2) == 0)
                    yield return Element;
            }
        }
    }
}
Decker
That is a buffered iterator; it would generally be preferable to use an iterator block instead - i.e. drop the `List<T>`, and just "yield return Element" instead of Add.
Marc Gravell
(for context, the original version had a List<T> with .Add, finishing in return; I prefer the updated version ;-p)
Marc Gravell