4

こんなに基本的なことを聞​​いても非難されないように願っています。グーグルで答えてもらえますが、教科書以外のことを聞きたいです。

IDictionaryキーがシーケンシャルであることを確認するための単体テストを作成しています。

KeysプロパティはであるためICollection<T>、コレクションを列挙して、キー値をコンソールに出力します。

for単純なループを使用してキー値を出力しようとする場合:

for (int i = 0; i < unPivotedData.Count; i++)
{
    Console.WriteLine(unPivotedData.Keys[i]);
}

次のコンパイルエラーが発生しました。

Cannot apply indexing with [] to an expression of type 'System.Collections.Generic.ICollection<int>'

ただし、foreachループを使用した場合:

foreach(int key in unPivotedData.Keys)
{
    Console.WriteLine(key);
}

すべてがうまくいきました。

インデクサーの機能と実装方法は理解していますが、どのように機能しforeachますか?foreachがどのように機能するかはまだわかりませんforが、コンパイラエラーが発生します。

ここで列挙の基本が欠けていますか?

乾杯!

編集:さらに、2つの間にパフォーマンスの違いはありますか?IDictionaryで使用できないことはわかっていforますが、IListを使用している場合は使用できます。forまたはよりも速く移動しますか、foreachまたはパフォーマンスの向上はごくわずかですか

4

7 に答える 7

8

foreach単に必要IEnumerableです。一方for(a,b,c)(あなたの場合)にはインデクサープロパティが必要です。

foreachを実装するオブジェクトを呼び出すと、内部IEnumerableでは が呼び出され、 IEnumeratorオブジェクトGetEnumerator()が返されます。そのオブジェクトは、や などのいくつかのメンバーを実装します。の各反復は実際に を呼び出しており、列挙子が前方に移動できる場合はを返し、移動できない (最後に到達した) 場合は false を返します。MoveNext()CurrentforeachMoveNext()true

ここで重要なのは、 を実装するオブジェクトはIEnumerable、それがいくつのアイテムを持っているか、それが置かれているアイテムのインデックスなどを知らないということです。それが知っているのは、次のアイテムに進むことができ、それを現在のアイテムとして返すことができるということだけです。それはアイテムを使い果たします。

for(a,b,c)一方、ループは本質的に永遠にループします。つまり、たまたま反復するコレクションによって制約されません (ただし、実際には通常はそうです) 。最も基本的なレベルでは、C毎回 1 回実行され、Btrue かどうかがチェックされます。true の場合B、再びループします。false の場合は停止します。ループするたびに、ループ内で を呼び出している可能性がobject[number]あります。オブジェクトにそのようなプロパティがない場合、もちろん失敗します。

ここで重要なのは、インデクサーを持つオブジェクトがランダム アクセスをサポートしていることです。つまり、いつでもそのオブジェクトを呼び出し[arbitrary index]て取得できます。これを と比較してください。これもまた、現在のIEnumerableアイテムにのみアクセスできます。

于 2009-09-21T18:03:36.253 に答える
4

ディクショナリの定義により、要素の順序が保証されないため、Keys コレクションにはインデックスが作成されません。残念ながら、これは、あなたが書いている単体テストの目的が根本的に間違っていることも意味します。

于 2009-09-21T18:30:34.467 に答える
3

IList<T>(インデックス作成をサポートする)とIEnumerable<T>次のような違いを考えることができます。

床中に物が散らばっている部屋があり、部屋の中のすべての物を取り戻してほしいと頼んだら、入って、順不同で物を拾い始めて、私に投げてください。順序は関係ありません。重要なのは、すべての項目を確認することです。この意味で、部屋のオブジェクトは、IEnumerableインターフェースを実装していると抽象的に考えることができます。それから、私がすべてのアイテムを部屋に戻し、もう一度やり直すように頼んだ場合、2回目にそれらを通過するときに、同じ順序でそれらを拾うという保証はありません。基本的に、これは「部屋のn番目のアイテムは何ですか?」と尋ねるのは意味がないためです。

これは次の点に関する重要な注意事項です。すべての呼び出しで同じ順序を使用しないIEnumerableケースは見たことがありforeachませんが、使用する必要はありませ

一方、部屋に特定の順序でオブジェクトを配置し、配置したのと同じ順序でオブジェクトをピックアップするように依頼する場合は、各オブジェクトに番号を割り当てるのが理にかなっています。「部屋に置いたn番目のアイテムは何ですか?」という質問。実際、この文脈では理にかなっています。したがって、このシナリオでは、部屋のオブジェクトはインターフェイスを実装していると考えることができIListます。

于 2009-09-21T18:38:47.800 に答える
1

Foreach は IEnumerable インターフェイスを使用します。ヘルプでその定義を参照すると、アイデアが得られます。

于 2009-09-21T18:05:41.283 に答える
1

他の人が述べているように、 foreach はコレクションの列挙子を使用するため、

foreach(int key in unPivotedData.Keys)
{
    Console.WriteLine(key);
}

次のように変換します。

IEnumerator enumerator = unPivotedData.Keys.GetEnumerator()
while(enumerator.MoveNext())
{
  Console.WriteLine(enumerator.Current);
}

ご覧のとおり、そこにはインデックスがありません。インデックス作成は、反復目的で使用できるイテレータとは非常に異なる獣です (for ループで試しているため) が、イテレータは反復のみのインデックス作成には使用できません。

于 2009-09-21T18:13:46.553 に答える
0

foreach は、カスタム Enumerator を提供するだけの IEnumerable インターフェイスを通過します。詳細については、 http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.aspxを参照してください。

基本的に、「現在」と「次に移動」を使用して、カスタム リンク リストのようなものとして機能します。

于 2009-09-21T18:07:44.913 に答える
0

C# ドキュメントのコレクションでの foreach の使用を参照してください。

于 2009-09-21T18:08:51.183 に答える