I found a situation when finally block is not called.
To the point:
using System;
using System.Collections.Generic;
using System.Threading;
using System.ComponentModel;
class MainClass{
static IEnumerable<int> SomeYieldingMethod(){
try{
yield return 1;
yield return 2;
yield return 3;
}finally{
Console.WriteLine("Finally block!");
}
}
static void Main(){
Example(7);
Example(2);
Example(3);
Example(4);
}
static void Example(int iterations){
Console.WriteLine("\n Example with {0} iterations.", iterations);
var e = SomeYieldingMethod().GetEnumerator();
for (int i = 0; i< iterations; ++i) {
Console.WriteLine(e.Current);
e.MoveNext();
}
}
}
And the result:
Example with 7 iterations.
0
1
2
3
Finally block!
3
3
3
Example with 2 iterations.
0
1
Example with 3 iterations.
0
1
2
Example with 4 iterations.
0
1
2
3
Finally block!
So, it looks like if someone is using my yielding method and works with it manually using enumerators (not with foreach) then my finally block can never be called.
Is there any way to ensure that my method finalizes it's resources? And is that a bug in "yield syntactic sugar" or does it work as it supposed to be?
A finally block will not execute due to other conditions like when JVM runs out of memory when our java process is killed forcefully from task manager or console when our machine shuts down due to power failure and deadlock condition in our try block.
It is a reserved keyword in C#. The finally block will execute when the try/catch block leaves the execution, no matter what condition cause it. It always executes whether the try block terminates normally or terminates due to an exception. The main purpose of finally block is to release the system resources.
The finally block always executes when the try block exits. This ensures that the finally block is executed even if an unexpected exception occurs.
A finally block always executes, regardless of whether an exception is thrown.
That is because they didn't use the iterator correctly. That code should be:
using(var e = SomeYieldingMethod().GetEnumerator())
{
for (int i = 0; i< iterations; ++i) {
Console.WriteLine(e.Current);
e.MoveNext();
}
}
The using
is important here. This is what maps to the finally
etc (assuming the iterator hasn't already finished naturally).
Specifically, foreach
explicitly calls Dispose()
on the iterator if the iterator implements IDisposable
. Since IEnumerator<T> : IDisposable
, this includes almost all iterators (caveat: foreach
does not require IEnumerator[<T>]
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With