foreach
?". The answer to this question usually sounds like this - “Implement an IEnumerable
”. The answer is correct, but not complete. In principle, this answer on the interview is enough and I have never met someone to consider it wrong. In fact, foreach
uses "duck typing" . In order for our class to work in foreach
enough to have the GetEnumerator
method returning something that has the MoveNext
method and the Current
property.foreach
compiler will honestly tell you what exactly is missing in this class.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
method to the container and enumerator class. 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
method and the Current
property to the enumerator. public class Enumerator { public bool MoveNext() { return false; } public object Current { get { return null; } } }
Current
property can return any type, both ref type
and value type
. Actually this was the reason for the use of "duck typing", at a time when there was no generics
, to avoid unnecessary boxing
and unboxing
.IDisposable
and in addition to general questions about manual resource management, there is a question about when the compiler can automatically call the Dispose
method. The answer we all know is that Dispose
is called automatically when using the using()
statement. The answer is correct, but incomplete! The Dispose
method can be called in two cases, in addition to using()
, it is called in the foreach
for the enumerator if the enumerator implements IDisposable
. using System; public class Enumerator : IDisposable { public bool MoveNext() { return false; } public object Current { get { return null; } } public void Dispose() { Console.WriteLine("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/209914/
All Articles