📜 ⬆️ ⬇️

Interesting moments in C # (foreach)

In this article we will briefly go through the features of foreach. You most likely know the first moment, you most likely do not know the second moment.

Previous article on Array

First moment


At the interviews they often ask - "What needs to be done in order for your class to work with 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.

It is not necessary to memorize these methods, if you drop your wrong class in foreach compiler will honestly tell you what exactly is missing in this class.
')
Examples

Test foreach :
 class Program { static void Main(string[] args) { var container = new Container(); foreach (var item in container) { } } } 

Wrong container:
 public class Container { } 

Compiler error:
foreach statement cannot operate on variables of type 'Container' because 'Container' does not contain a public definition for 'GetEnumerator'

Add the GetEnumerator method to the container and enumerator class.

The correct container:
 public class Container { public Enumerator GetEnumerator() { return new Enumerator(); } } 

Wrong enumerator:
 public class Enumerator { } 

Compiler error:
foreach requires that the return type 'Enumerator' of 'Container.GetEnumerator()' must have a suitable public MoveNext method and public Current property

Add the MoveNext method and the Current property to the enumerator.

The correct enumerator is:
 public class Enumerator { public bool MoveNext() { return false; } public object Current { get { return null; } } } 


Now the compiler is happy with everything.

Note:
The 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 .

Second moment


At the interview, there are questions about 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 .

Examples

Dispose enumerator:
 using System; public class Enumerator : IDisposable { public bool MoveNext() { return false; } public object Current { get { return null; } } public void Dispose() { Console.WriteLine("Dispose"); } } 


Now when you run the example, we will see the “Dispose” line in the console.

For those who are interested, here is the code that generates the compiler for our case:
 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(); } 

Thank you all for your attention!

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


All Articles