この記事では、foreachの機能について簡単に説明します。 最初の瞬間を知っている可能性が最も高く、2番目の瞬間を知っていない可能性が高くなります。
配列に関する以前の記事最初の瞬間
インタビューでは、「クラスを
foreach動作させるには何をする必要がありますか?」 この質問に対する答えは通常、次のように聞こえます-"
IEnumerable "。 この答えは正しいですが、完全ではありません。 原則として、インタビューでのこの回答は十分であり、私はそれを間違っていると考える人に会ったことがありません。 実際、
foreachは
ダックタイピングを使用し
ます 。 クラスを
foreach 、
MoveNextメソッドと
Currentプロパティを持つものを返す
GetEnumeratorメソッドを用意すれば十分
GetEnumerator 。
間違ったクラスを
foreachスリップさせた場合、これらのメソッドを覚えておく必要はありません。コンパイラは、このクラスに欠けているものを正確に教えてくれます。
例
foreachテストします。
class Program { static void Main(string[] args) { var container = new Container(); foreach (var item in container) { } } }
間違ったコンテナ:
public class Container { }
コンパイラエラー:
foreach statement cannot operate on variables of type 'Container' because 'Container' does not contain a public definition for 'GetEnumerator'GetEnumeratorメソッドをコンテナおよび列挙子クラスに追加します。
正しいコンテナ:
public class Container { public Enumerator GetEnumerator() { return new Enumerator(); } }
不正な列挙子:
public class Enumerator { }
コンパイラエラー:
foreach requires that the return type 'Enumerator' of 'Container.GetEnumerator()' must have a suitable public MoveNext method and public Current propertyMoveNextメソッドと
Currentプロパティを列挙子に追加します。
正しい列挙子:
public class Enumerator { public bool MoveNext() { return false; } public object Current { get { return null; } } }
これでコンパイラは問題ありません。
注:
Currentプロパティは、 ref typeとvalue type両方の任意の型を返すことができvalue type 。 実際、これが、不要なboxingとunboxingを回避するために、 genericsがないときにアヒルタイピングを使用する理由でした。第二の瞬間
インタビューでは、
IDisposableに関する質問があり、手動のリソース管理に関する一般的な質問に加えて、コンパイラが
Disposeメソッドを自動的に呼び出すことができる時期についての質問があります。 答えはわかっています
Dispose using()ステートメントを使用すると、
Disposeが自動的に呼び出されます。 この答えは正しいですが、不完全です!
Disposeメソッドは、
using()に加えて、列挙子が
IDisposable実装している場合、列挙子の
foreachで呼び出される2つの場合に
Disposeことができます。
例
Disposeを使用する
Dispose :
using System; public class Enumerator : IDisposable { public bool MoveNext() { return false; } public object Current { get { return null; } } public void Dispose() { Console.WriteLine("Dispose"); } }
この例を実行すると、コンソールに「Dispose」行が表示されます。
興味のある方のために、ここにコンパイラが私たちのケースのために生成するコードがあります:
Container container = new Container(); Enumerator enumerator = container.GetEnumerator(); try { while (enumerator.MoveNext()) { var element = enumerator.Current;
ご清聴ありがとうございました!