guogangj
guogangj

Reputation: 2435

yield return and try-catch.(C#)

I met a very odd problem. The following code doesn't run anticipated.

static IEnumerable<int> YieldFun()
{
    int[] numbers = new int[3] { 1, 2, 3 };

    if(numbers.Count()==3)
        throw new Exception("Test...");

    //This code continues even an exception was thrown above.
    foreach(int i in numbers)
    {
        if(i%2==1)
            yield return numbers[i];
    }
}

static void Main(string[] args)
{
    IEnumerable<int> result = null;
    try
    {
        result = YieldFun();
    }
    catch (System.Exception ex) //Cannot catch the exception
    {
        Console.WriteLine(ex.Message);
    }


    foreach (int i in result)
    {
        Console.Write(" " + i);
    }
}

two questions. First, YieldFun seems continue to work even an exception has been thrown. Second, the caller's try-catch block cannot catch the thrown exception.

Why this? and how to solve this?

Upvotes: 3

Views: 1750

Answers (2)

Colin Smith
Colin Smith

Reputation: 12540

You can do this to separate out the deferred part (the scope that contains the yield causes an iterator to be built)....and have your checks executed when the assignment happens.

static IEnumerable<int> YieldFun()
{
    int[] numbers = new int[3] { 1, 2, 3 };

    if (numbers.Count() == 3)
        throw new Exception("Test...");

    return YieldFunImpl(numbers);
}

static IEnumerable<int> YieldFunImpl(int []numbers)
{
    //This code continues even an exception was thrown above.
    foreach (int i in numbers)
    {
        if (i % 2 == 1)
            yield return numbers[i];
    }
}

static void Main(string[] args)
{
    IEnumerable<int> result = null;
    try
    {
        result = YieldFun();
    }
    catch (System.Exception ex) //Cannot catch the exception
    {
        Console.WriteLine(ex.Message);
    }

    if (result != null)
    {
        foreach (int i in result)
        {
            Console.Write(" " + i);
        }
    }
}

}

When the Exception goes off (because your Count() == 3)....your catch will be called, and your result will not be set....so when the for loop tries to iterate the result...it will be null....you need to add a null check.

Upvotes: 3

Alexei Levenkov
Alexei Levenkov

Reputation: 100547

This is caused by delayed execution of iterator. Your exception is thrown later than you think: foreach (int i in result) tries to iterate and throws, but you don't catch exception there.

Body of the function is not executed till one tries to iterate items. So just calling this function does not actually reach "throw ..." statement. You can manually iterate result to see at what exact point the exception is thrown.

Upvotes: 6

Related Questions