2

IEnumeratorとIEnumerableを実装するコレクションクラスを開発しています。

私の最初のアプローチでは、それらを直接実装しました。これで、yieldキーワードを発見し、IEnumerator / IEnumerableインターフェイスを、yieldを使用してループ内でIEnumerableを返す読み取り専用プロパティValuesに置き換えて、すべてを単純化することができました。

私の質問:IEnumerable / IEnumeratorを実装せずに、クラス自体を反復処理できるような方法でyieldを使用することは可能ですか?

つまり、フレームワークコレクションと同様の機能が必要です。

List<int> myList = new List<int>();
foreach (int i in myList)
{
    ...
}

これは可能ですか?

更新:私の質問はひどい言い回しだったようです。IEnumeratorまたはIEnumerableを実装してもかまいません。私はそれを行う唯一の方法は古いCurrent/MoveNext/Resetメソッドを使用することだと思っていました。

4

2 に答える 2

9

実装したり、仕事に取り掛かったりする必要はありません、そうすることをお勧めします。行うのは非常に簡単です:IEnumerable<T>IEnumerableforeach

public class Foo : IEnumerable<Bar>
{
    public IEnumerator<Bar> GetEnumerator()
    {
        // Use yield return here, or 
        // just return Values.GetEnumerator()
    }

    // Explicit interface implementation for non-generic
    // interface; delegates to generic implementation.
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

実装しない代替手段はIEnumerable<T>、プロパティを呼び出すだけですValuesが、それでもGetEnumerator()メソッドを提供します。

public class Foo
{
    public IEnumerator<Bar> GetEnumerator()
    {
        // Use yield return here, or 
        // just return Values.GetEnumerator()
    }
]

IEnumerable<T>これは機能しますが、LINQ to Objectsなど、を期待するものにコレクションを渡すことができないことを意味します。

適切なメンバーを持つ型を返すメソッドをforeachサポートするすべての型で機能することは、あまり知られていない事実です。これは、ジェネリックスの前に強く型付けされたコレクションを許可するためであり、コレクションを反復処理しても値型などはボックス化されません。IMO、今は本当に必要ありません。GetEnumerator()MoveNext()Current

于 2011-05-26T09:00:19.493 に答える
1

あなたはこのようなことをすることができますが、なぜですか?IEnumeratorすでに簡単です。

Interface MyEnumerator<T>
{
    public T GetNext();
}

public static class MyEnumeratorExtender
{
    public static void MyForeach<T>(this MyEnumerator<T> enumerator,
        Action<T> action)
    {
        T item = enumerator.GetNext();
        while (item != null)
        {
            action.Invoke(item);
            item = enumerator.GetNext();
        }
    }
}

私はむしろinキーワードを持っていて、linqを書き直したくありません。

于 2011-05-26T09:32:10.757 に答える