2

この質問は、オブジェクトを反復処理するときにオブジェクトを変更して IEnumerable インターフェイスを悪用することに関して私が提起した別の質問に便乗しています。

一般的なコンセンサスは、IEnumerable を実装するものはべき等であってはならないということです。しかし、.net は foreach ステートメントを使用したコンパイル時のダック タイピングをサポートしています。IEnumerator GetEnumerator() メソッドを提供するすべてのオブジェクトは、foreach ステートメント内で使用できます。

GetEnumerator メソッドはべき等であるべきですか、それとも IEnumerable を実装するときですか?

編集 (追加されたコンテキスト)

私が提案しているのは、キューを反復処理するときに、各アイテムがキューから取り出されるということです。さらに、GetEnumerator の呼び出し後にキューにプッシュされた新しいオブジェクトは、引き続き反復処理されます。

4

4 に答える 4

3

べき等であるタイプではありません-それはあまり意味がありません。あなたは不変を意味するかもしれませんが、それは明確ではありません。通常、べき等であるのはGetEnumeratorメソッド自体です。

通常はそうだと思いますが、べき等ではない方法を使用することが理にかなっている特殊なケースを想定できGetEnumeratorます。たとえば、一度しか読み取れないデータがある可能性があります(同じリクエストを再度処理しないWebサーバーからストリーミングしているためなど)。その場合、GetEnumeratorデータソースを効果的に無効にする必要があるため、今後の呼び出しで例外がスローされます。

もちろん、そのようなタイプと方法は非常に注意深く文書化する必要がありますが、それらは合理的だと思います。

于 2010-11-16T14:06:38.433 に答える
3

この議論は古いものであり、私の知る限り、共通のコンセンサスはありません。

foreach(ランタイム) ダックタイピングの概念を、目的のセマンティクスをサポートするためにサポートされているコンパイラを悪用することと混同しないでください。

あなたが混乱しているように見えるもう1つの概念は、冪等性と不変性です。あなたの言い回しによれば、2番目を説明しようとします。これは、列挙子を提供するオブジェクトが列挙中に変更されることを意味します。一方、冪等性は列挙子を意味し、2 回呼び出されたときに同じ結果が得られます。

これについて明確になったので、IEnumerable 操作がサポートするセマンティクスを慎重に決定する必要があります。特定の種類の列挙は冪等にするのが難しく (つまり、キャッシュが必要)、通常は次のカテゴリのいずれかに分類されます。

  • ランダムに変化するデータ (つまり、乱数ジェネレーター、センサー ストリーム) の列挙
  • 共有状態の列挙 (ファイル、データベース、ストリームなど)

一方、これは「ソース」操作のみを説明します。列挙子を使用してフィルター操作または変換操作を実装している場合は、常に冪等にするようにしてください。

于 2010-11-16T14:15:52.673 に答える
0

コレクションで ForEach を使用しても、コレクション型の名前がそれが起こることを暗示していない限り、コレクションを変更しないことをお勧めします。私の頭の中の問題は、コレクションを列挙可能なものに消費するメソッドが実行された場合に返されるものです(たとえば、「MyThing.DequeueAsEnumの各Foo」を許可するため)。DequeueAsEnum が iEnumerable を返す場合、誰かが "Dim myIEnumerable As IEnumerable = MyThing.DequeueAsEnum" を回避し、2 つの互いに素な For-Each ループで MyIEnumerable を使用することを期待できます。DequeueAsEnum が EnumerableOnlyOnce 型を返す場合、その戻り値を一度だけ列挙する必要があることが少し明確になります。確かに、新しい C# と VB には暗黙的な型付けが存在します。

ところで、クラス参照が変数に格納されないようにすることが役立つ状況がいくつかあります。外部コードがそのクラス型の式を使用できるようにクラスを宣言する方法はありますが、その変数を宣言することはできませんか?

于 2010-11-27T18:23:15.377 に答える
0

素敵なワンライナーですべてのアイテムをデキューできるキュー クラスが必要なようです。

この考え自体には何の問題もありません。GetEnumeratorあなたが求めているものを達成するために具体的に使用するというあなたの好みに疑問を呈します。

それが何をするかという点でより明示的なメソッドを単純に書かないのはなぜですか? たとえば、、DequeueAllまたはそのようなものです。

例:

// Just a simplistic example. Not the way I'd actually write it.
class CustomQueue<T> : Queue<T>
{
    public IEnumerable<T> DequeueAll()
    {
        while (Count > 0)
        {
            yield return Dequeue();
        }
    }
}

(上記は、によってすでに提供されているものを超えて必要な唯一の機能を文字通り表す場合、拡張メソッドである可能性があることに注意してください。)Queue<T>

このようにして、非べき等の(潜在的な)混乱なしに、あなたが求めていると思われる「クリーン」なコードを取得できますGetEnumerator

// Pretty clean, right?
foreach (T item in queue.DequeueAll())
{
    Console.WriteLine(item);
}
于 2010-11-16T14:56:24.183 に答える