IENUMERABLEおよびIENUMERATORに関する質問
-
13-10-2019 - |
質問
次のコードを使用して、MyClassがForeachを使用できるようにします。しかし、私はプログラミングにかなり慣れておらず、次のコードを理解するのが困難です。コメントで問題を説明しました。情報を提供してくれてありがとう。
public class MyClass : IEnumerable<string>
{
//1) What is IEnumerator for?
// Whats the difference between IEnumerator and IEnumerable
public IEnumerator<string> GetEnumerator()
{
yield return "first";
yield return "second";
}
//2) What is it for? It just calls above method
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
//3) Lastly what benefits I have from implementing genetic interface
//IEnumerable<string> instead of just IEnumerable
解決
IEnumeratorとIEnumerableの違いは何ですか?
ジェイソンの答えは良いですが、私はこれについてどう思うかを追加するだけだと思いました。あなたがシーケンスを持っていると想像してください:
1, 1, 2, 3, 5, 8, 13, ...
次に、そのシーケンスのある位置を指している矢印があると想像してください。
1, 1, 2, 3, 5, 8, 13, ...
^
「矢印」は、2つのことを行うことができるオブジェクトです。まず、それが指しているものをあなたに与えることができます。第二に、それは次のことを指摘することができます。
IENUMERATORは矢です。それはあなたにそれが指しているものをあなたに与えるプロパティを持っています。メソッド、movenext()があり、次のことを指摘します。
そもそもどうやって矢を手に入れますか?矢印工場が必要です。工場に矢印を尋ねると、シーケンスの最初の要素を指す矢印が与えられます。
Ienumerableは矢印工場です。それには、シーケンスの最初の要素への矢印を与える方法、getEnumeratorがあります。
このスキームの優れた特性は、同じシーケンス内の異なる場所を指す複数の矢印を持つことができることです。
Ienumerableではなく、一般的なインターフェイスを実装することの利点は何ですか?
シーケンスが整数であると仮定します。実装する場合 IEnumerable
それからあなたが言うとき
foreach(int x in mysequence)
それが実際に行うのは、シーケンスでintをオブジェクトに変換し、整数をボクシングし、すぐにオブジェクトを整数に戻し、すべての操作に完全に不要なメモリ割り当てを追加することです。コンパイラがシーケンスが整数であることを知っている場合、不必要なボクシング操作をスキップできます。
シーケンスが文字列のものであると仮定します。実装する場合 IEnumerable<string>
それからあなたは言うことができます:
string first = mysequence.First();
そうでない場合は、言わなければなりません
string first = (string)mysequence.First();
これは不必要でエラーが発生しやすいです。キャストを介してコンパイラにタイプが文字列であることを指示するのではなく、単に 保証 タイプはタイプシステムを使用して文字列であること。
他のヒント
1)何ですか
IEnumerator
にとって?違いは何ですかIEnumerator
とIEnumerable
?
IEnumerator
シーケンスを列挙できるメソッドを表すインターフェイスです。間の違い IEnumerator
と IEnumerable
前者は、シーケンスを列挙できるオブジェクトの契約を表しており、後者は列挙できるシーケンスであるオブジェクトの契約を表します。
public IEnumerator<string> GetEnumerator() {
yield return "first";
yield return "second";
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
2)それは何のためですか?上記の方法を呼び出すだけです。
前者は、メソッドの実装を表しています GetEnumerator
契約について IEnumerable<string>
. 。後者は、メソッドの明示的な実装を表しています GetEnumerator
契約について IEnumerable
. 。問題は、両方の契約に名前が付いた方法があることです GetEnumerator
ただし、さまざまなリターンタイプがあるため、メソッドは両方の契約を同時に満たすことができないようにします(すべてのクラス実装 IEnumerable<T>
また、実装する必要があります IEnumerable
なので IEnumerable<T> : IEnumerable
)。後者はの実装を呼び出します IEnumerable<string>.GetEnumerator
それは、anを返す賢明な実装であるためです IEnumerator
なので IEnumerator<string> : IEnumerator
.
3)最後に、ジェネリックインターフェイスの実装からどのような利点がありますか
IEnumerable<string>
ただの代わりにIEnumerable
?
強いタイピング。あなたは、順番の要素を知っています IEnumerable<string>
すべてのインスタンスです String
一方、あなたはそれを知りません IEnumerable
そして、後者の要素をのインスタンスにキャストしようとすることになります String
できないとき。
これが宣言です IEnumerable<T>
:
public interface IEnumerable<out T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
あなたには選択肢がありません、あなた 持ってる 非世のIENUMERABLEインターフェイスも実装します。 iEnumerable.getEnumerator()実装を省略すると、コンパイルエラーが表示されます。これは、ジェネリックがまだ利用できない.NET 1.x日から残った手荷物であり、.NET 1.xアセンブリとの相互作用をサポートするために必要な.NET 2.0の移行期間から残っています。私たちはそれに固執しています。
1)IENUMERATORとは何ですか?
IEnumeratorは、movenext()および現在のメンバーとの実際の作業部分です。
IEnumeratorとIEnumerableの違いは何ですか
IENumerableは、getEnumerator()があることを示すコレクションのインターフェイスです。
2)[非generic getEnumerator]それは何のためですか?上記の方法を呼び出すだけです
非遺伝子法は、後方互換性のためだけにあります。明示的な実装を使用することにより、可能な限り「見えない」と移動することに注意してください。必要なので実装してから忘れてください。
3)最後に、単なるienumerableではなく、遺伝的インターフェイスを実装することからどのような利点がありますかienumerable
で使用する場合 foreach
Adavantageは小さいです。Foreachはループ変数をキャストします。使用できます var
foreach:
foreach (var s in myClassInstance) // needs `IEnumerable<string>`
foreach (string s in myClassInstance) // works with `IEnumerable` as well
しかし、と IEnumerable<string>
また、他の領域、特にlinqへのタイプセーフインターフェイスもあります。
MyClass mc = new MyClass ();
string s = mc.FirstOrDefault();
GetEnumerator
既存のコードを破らないように、ジェネリックが言語に導入される前から存在しています。
一般的な列挙では、クラスの消費者は、反復時に各アイテムを弦にキャストする必要はありません。
3番目の質問(なぜジェネリックを使用するのか)については、ここにいくつかの答えがあります。
一般的なコレクションを使用して、安全性とパフォーマンスを向上させる必要がありますか?
要するに、できる限り一般的なコレクションを使用してください。