C#の興味深い瞬間(foreach)

この記事では、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 property







MoveNext



メソッドと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; //  foreach } } finally { IDisposable disposable = enumerator as IDisposable; if (disposable != null) disposable.Dispose(); }
      
      





ご清聴ありがとうございました!



All Articles