クラスがiNumerableを実装していない場合、getEnumeratorメソッドが依然としてidempotentである必要があります

StackOverflow https://stackoverflow.com/questions/4194900

質問

この質問は別の背中を豚の背中にします 質問 私は、オブジェクトを反復するときにオブジェクトを変更することにより、ienumerableインターフェイスを乱用することに関して提起しました。

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

getEnumeratorメソッドは等程度であるべきですか、それともienumerableを実装するときですか?

編集(コンテキストの追加)

私が提案していることをこれに回すために、キューを繰り返すと、各アイテムが繰り返されるように除外されているということです。さらに、GetEnumeratorへの呼び出し後にキューに押し込まれた新しいオブジェクトは、まだ反復されます。

役に立ちましたか?

解決

そうではありません タイプ これは心臓病です - それはあまり意味がありません。あなた 五月 不変ですが、それは明確ではありません。それはです GetEnumerator 通常、等量である方法自体。

そうだと思います 通常 ケース、私は非公開を持っていることが理にかなっている特別なケースを想像することができます GetEnumerator 方法。たとえば、1回しか読めないデータを持っている可能性があります(同じリクエストを再度サービスしないWebサーバーからストリーミングしているため、またはそのようなものです。その場合、 GetEnumerator 将来の呼び出しが例外をスローするように、データソースを効果的に無効にする必要があります。

もちろん、このようなタイプと方法は非常に慎重に文書化されるべきですが、合理的だと思います。

他のヒント

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

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

あなたが混乱させると思われるもう1つの概念は、慣習と不変性です。あなたの言葉遣いによれば、あなたは2番目を説明しようとします。つまり、列挙器を提供するオブジェクトが列挙中に変更されます。一方、idempotenceは列挙器を意味し、2回呼び出すと同じ結果が得られます。

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

  • ランダムに変更されたデータ(つまり、乱数ジェネレーター、センサーストリーム)を列挙する
  • 共有状態を介して列挙しています(例:ファイル、データベース、ストリームなど)

一方、これは「ソース」操作のみを占めています。列挙器を使用してフィルターまたは変換操作を実装している場合は、常にそれらをiDempotentにしようとする必要があります。

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

このアイデア自体には何の問題もありません。特に使用することがあなたの好みに疑問を呈しています 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();
        }
    }
}

(上記はanである可能性があることに注意してください 拡張法, 、それが文字通りを表す場合 それだけ 既に提供されているものを超えて必要な機能 Queue<T>.)

このように、あなたはまだ「きれいな」見えるコードを取得することができます。 GetEnumerator:

// Pretty clean, right?
foreach (T item in queue.DequeueAll())
{
    Console.WriteLine(item);
}

コレクションでforeachを使用することは、コレクションタイプの名前がそれが起こることを意味しない限り、それを変更するべきではないことをお勧めします。私の心の問題は、コレクションを列挙可能なものに消費する方法を実行した場合に返されるべきものです(例:「mything.dequeueasenumの各fooについて」)。 dequeueasenumがienumerableを返す場合、誰かが「ienumerable = mything.dequeueasenumのように薄暗いmyienumerable」で逃げることを期待することができ、その後、2つのumoint for-eachループでmyEnumerableを使用します。 dequeueasenumがタイプの列挙可能onlyOnceを返す場合、その返品を1回のみ列挙する必要があることが少し明確になります。確かに、新しいC#およびVB.NET方言での暗黙のタイピングの存在により、誰かが機能するべきではないときに変数に戻すことを割り当てる可能性が少し高くなりますが、それを防ぐ方法がわかりません。

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top