web-dev-qa-db-ja.com

IEnumerable <T>を返すIEnumerable <T>の拡張メソッドを定義しますか?

IEnumerable<T>を返すIEnumerable<T>の拡張メソッドを定義するにはどうすればよいですか?目標は、拡張メソッドをすべてのIEnumerableおよびIEnumerable<T>で使用できるようにすることです。ここで、Tは匿名型にすることができます。

23

イテレータを作成する最も簡単な方法は、次のようにイテレータブロックを使用することです。

_static IEnumerable<T> Where<T>(this IEnumerable<T> data, Func<T, bool> predicate)
{
    foreach(T value in data)
    {
        if(predicate(value)) yield return value;
    }
}
_

ここで重要なのは「_yield return_」です。これはメソッドをイテレーターブロックに変換し、コンパイラーは同じことを行う列挙子(_IEnumerator<T>_)を生成します。呼び出されると、ジェネリック型推論はTを自動的に処理するため、次のものが必要です。

_int[] data = {1,2,3,4,5};
var odd = data.Where(i=>i%2 != 0);
_

上記は匿名タイプで問題なく使用できます。

当然のことながら、必要に応じてTを指定できます(匿名でない限り)。

_var odd = data.Where<int>(i=>i%2 != 0);
_

IEnumerable(非ジェネリック)に関しては、最も簡単なアプローチは、呼び出し元が.Cast<T>(...)または.OfType<T>(...)を使用して最初に_IEnumerable<T>_を取得することです。上記で_this IEnumerable_を渡すことができますが、呼び出し元はコンパイラーに推測させるのではなく、Tを自分で指定する必要があります。 Tが匿名型である場合、これを使用することはできません。したがって、ここでの教訓は、匿名型でIEnumerableの非一般的な形式を使用しないことです。

メソッドのシグネチャがコンパイラがTを識別できないような、もう少し複雑なシナリオがいくつかあります(もちろん、匿名タイプに指定することはできません)。そのような場合、通常、コンパイラーcanが推論で使用する別の署名にリファクタリングすることは可能ですが(おそらくパススルーメソッドを介して)、 dここに答えを提供するために実際のコードを投稿する必要があります。


(更新しました)

議論に続いて、匿名タイプで_Cast<T>_を活用する方法があります。重要なのは、型推論に使用できる引数を提供することです(引数が使用されない場合でも)。例えば:

_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);
}
_
39
Marc Gravell
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;
            }
        }
    }
}
4
Howard Pinsley

この投稿は、始めるのに役立つかもしれません: 一般的に型指定されたクラスのC#拡張メソッドをどのように記述しますか 。それがまさにあなたが探しているものであるかどうかはわかりませんが、それはあなたが始めるかもしれません。

0
Nathan W