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

この記事では、foreachの機能について簡単に説明します。 最初の瞬間を知っている可能性が最も高く、2番目の瞬間を知っていない可能性が高くなります。

配列に関する以前の記事

最初の瞬間


インタビューでは、「クラスをforeach動作させるには何をする必要がありますか?」 この質問に対する答えは通常、次のように聞こえます-" IEnumerable "。 この答えは正しいですが、完全ではありません。 原則として、インタビューでのこの回答は十分であり、私はそれを間違っていると考える人に会ったことがありません。 実際、 foreachダックタイピングを使用します 。 クラスをforeachMoveNextメソッドと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 typevalue type両方の任意の型を返すことができvalue type 実際、これが、不要なboxingunboxingを回避するために、 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(); } 

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

Source: https://habr.com/ru/post/J209914/


All Articles