C#は、C ++イテレータのような列挙子の種類の違いから恩恵を受けますか?

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

  •  06-07-2019
  •  | 
  •  

質問

IEnumerator.Reset()メソッドについて考えてきました。 MSDNのドキュメントで、COM相互運用のためだけにあることを読みました。 C ++プログラマーとしては、IEnumeratorをサポートするResetフォワードイテレータPrintContentsをサポートしない<=>は実際には入力反復子

だから私の質問の一部は、この理解は正しいですか?

質問の2番目の部分は、入力イテレータと前方イテレータ(または<!> quot; enumerators <!> quot;を区別した場合)がC#でメリットがあるかどうかです。このイテレータのクローンに関する質問

編集:前方および入力反復子の明確化。入力反復子は、コレクションのメンバー(またはジェネレーター関数または入力ストリームから)を1回だけ列挙できることを保証します。これは、C#でIEnumeratorが正確に機能する方法です。 2回目に列挙できるかどうかは、<=>がサポートされているかどうかによって決まります。前方反復子には、この制限はありません。必要な回数だけメンバーを列挙できます。

一部のC#プログラマーは、マルチパスアルゴリズムで<=>を確実に使用できない理由を過小評価していない。次の場合を考慮してください。

void PrintContents(IEnumerator<int> xs)
{
  while (iter.MoveNext())
    Console.WriteLine(iter.Current); 
  iter.Reset();
  while (iter.MoveNext())
    Console.WriteLine(iter.Current); 
}

このコンテキストで<=>を呼び出しても問題ありません:

List<int> ys = new List<int>() { 1, 2, 3 }
PrintContents(ys.GetEnumerator()); 

ただし、次を見てください:

IEnumerable<int> GenerateInts() {   
  System.Random rnd = new System.Random();
  for (int i=0; i < 10; ++i)
    yield return Rnd.Next();
}

PrintContents(GenerateInts());

<=>が<=>をサポートした場合、言い換えるとマルチパスアルゴリズムをサポートした場合、コレクションを反復処理するたびに異なります。これは、予期しない動作になるため、望ましくありません。この例は少し偽造されていますが、実際には発生します(ファイルストリームからの読み取りなど)。

役に立ちましたか?

解決

興味深い質問。私の見解では、もちろんC#はメリットになります。ただし、追加するのは簡単ではありません。

C ++には、はるかに柔軟な型システムのため、区別があります。 C#では、オブジェクトを複製する堅牢な一般的な方法はありません。これは、前方反復子を表すために必要です(マルチパス反復をサポートするため)。そしてもちろん、これが本当に役立つためには、双方向およびランダムアクセスの反復子/列挙子もサポートする必要があります。そして、それらすべてをスムーズに機能させるには、C ++テンプレートにあるようなダックタイピングの何らかの形が本当に必要です。

最終的に、2つの概念の範囲は異なります。

C ++では、イテレータは、値の範囲について知る必要があるすべてのものを表すことになっています。イテレータのペアを考えると、元のコンテナは必要ではありません。好きなだけ要素を並べ替えたり、検索したり、操作したりコピーしたりできます。元のコンテナは画像から外れています。

C#では、列挙子はそれほど多くのことを行うことを意図していません。最終的には、これらは直線的にシーケンスを実行できるように設計されています。

Reset()に関しては、そもそもそれを追加するのは間違いであったことが広く受け入れられています。正しく機能し、正しく実装されていれば、はい、列挙子は前方反復子に類似していると言えますが、一般的には、間違いとして無視するのが最善です。そして、すべての列挙子は入力反復子にのみ似ています。

残念ながら。

他のヒント

Resetは大きな間違いでした。 IEnumerable<T>でシェナンガンと呼びます。私の意見では、<!> quot; forward iterator <!> quot;の違いを反映する正しい方法です。および<!> quot; input iterators <!> quot; .NETタイプシステムでは、IEnumerator<T>と<=>が区別されます。

こちらもご覧ください回答では、MicrosoftのEric Lippert(非公式の能力では、間違いなく、彼はこれが設計ミスであると主張する必要があるよりも多くの資格を持つ人であるということだけです)は、コメントで同様のポイントを示しています。 この素晴らしいブログもご覧ください。

C#の観点から:

IEnumeratorを直接使用することはほとんどありません。通常は、foreachを期待するIEnumerableステートメントを実行します。

IEnumerable _myCollection;
...
foreach (var item in _myCollection) { /* Do something */ }

Reset()も渡さないでください。反復が必要なコレクションを渡したい場合は、<=>を渡します。 <=>には<=>を返す単一の関数があるため、コレクションを複数回(複数のパス)反復するために使用できます。

<=>に<=>関数は必要ありません。最初からやり直す場合は、古いもの(収集されたガベージ)を捨てて新しいものを取得するだけです。

.NETフレームワークは、サポートできる機能とその約束についてIEnumerator<T>に問い合わせる手段があれば、非常に有益です。このような機能はIEnumerable<T>でも役立ちますが、列挙子の質問をすることができると、ReadOnlyCollectionのようなラッパーから列挙子を受け取ることができるコードは、ラッパーを関与させることなく、改善された方法で基になるコレクションを使用できます。

全体を列挙することができ、大きすぎないコレクションの列挙子がある場合、それからReadOnlyCollection<T>を生成し、常に同じアイテムのシーケンス(特に残りのアイテムのセット)を生成できます列挙子内のすべてのコンテンツを配列に読み込み、列挙子を破棄して破棄し、配列から列挙子を取得し(元の放棄された列挙子の代わりにそれを使用して)、配列を<=>でラップして返します。このようなアプローチは、上記の条件を満たすあらゆる種類の列挙可能なコレクションで機能しますが、それらのほとんどではひどく非効率的です。列挙子に不変の<=>で残りのコンテンツを生成するように依頼する手段があると、多くの種類の列挙子が指定されたアクションをより効率的に実行できるようになります。

そうは思いません。 IEnumerable前方反復子、および入力反復子を呼び出します。後方に移動したり、基になるコレクションを変更したりすることはできません。 foreachキーワードの追加により、ほとんどの場合、イテレータはほとんど考えられません。

意見: 入力イテレータ(各イテレータを取得)と出力イテレータ(各イテレータに何かを行う)の違いは、フレームワークへの追加を正当化するにはあまりにも些細です。また、出力反復子を実行するには、デリゲートを反復子に渡す必要があります。入力イテレータは、C#プログラマにとってより自然なようです。

プログラマがランダムアクセスを希望する場合はIList<T>もあります。

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