Interesting moments in C # (foreach)
In this article, we briefly go over the features of foreach. You most likely know the first moment, you most likely do not know the second moment.
Previous article about Array
At interviews they often ask - “What needs to be done to make your class work with
Remembering these methods is not necessary if you slip your wrong class into the
Test
Wrong container:
Compiler Error:
Add a method
The correct container:
Incorrect enumerator:
Compiler Error:
Add a method
The correct enumerator:
Now the compiler is fine.
Note:
The property
At the interview there are questions about
Enumerator with
Now when we run the example, we will see the “Dispose” line in the console.
For those who are interested, here is the code that the compiler generates for our case:
Thank you all for your attention!
Previous article about Array
First moment
At interviews they often ask - “What needs to be done to make your class work with
foreach
?”. The answer to this question usually sounds like this - "Implement IEnumerable
." This answer is correct, but not complete. In principle, this answer at the interview is enough and I have never met anyone to consider it wrong. In fact, it foreach
uses duck typing . In order for our class to work in, it is foreach
enough to have a method that GetEnumerator
returns something that has a method MoveNext
and property Current
. Remembering these methods is not necessary if you slip your wrong class into the
foreach
compiler honestly tells 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 a method
GetEnumerator
to the container and enumerator class. The correct container:
public class Container
{
public Enumerator GetEnumerator()
{
return new Enumerator();
}
}
Incorrect 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 a method
MoveNext
and property Current
to the enumerator. The correct enumerator:
public class Enumerator
{
public bool MoveNext()
{
return false;
}
public object Current
{
get { return null; }
}
}
Now the compiler is fine.
Note:
The property
Current
can return any type as ref type
and so value type
. Actually, this was the reason for the use of "duck typing", at a time when it was not 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 a method Dispose
. We all know the answer - it is Dispose
called automatically when using the operator using()
. This answer is correct, but incomplete! A method Dispose
can be called in two cases, in addition using()
, it is called in foreach
for the enumerator, if the enumerator implements IDisposable
.Examples
Enumerator with
Dispose
: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 we run the example, we will see the “Dispose” line in the console.
For those who are interested, here is the code that the compiler generates 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!