Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finally block may not be called when enumerating over yielding method [duplicate]

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?

like image 629
PanDenat Avatar asked Nov 12 '13 13:11

PanDenat


People also ask

In which condition finally block will not be executed?

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.

When finally block is not executed in C#?

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.

When finally block is executed?

The finally block always executes when the try block exits. This ensures that the finally block is executed even if an unexpected exception occurs.

Is finally block always executed?

A finally block always executes, regardless of whether an exception is thrown.


1 Answers

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>]).

like image 167
Marc Gravell Avatar answered Sep 29 '22 11:09

Marc Gravell