yield return和try-catch(C#)

3

我遇到了一个非常奇怪的问题。下面的代码并没有按照预期运行。

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);
    }
}

两个问题: 首先,即使抛出异常,YieldFun似乎仍在继续工作。 其次,调用者的try-catch块无法捕获抛出的异常。

为什么会这样?如何解决这个问题?

2个回答

6
这是由于迭代器的延迟执行引起的。你的异常被抛出的时间比你想象的要晚: foreach (int i in result) 尝试进行迭代并抛出异常,但你没有在那里捕获异常。

直到尝试迭代项目时才会执行函数体。因此,仅调用此函数实际上并没有到达“throw…”语句。你可以手动迭代结果,以查看异常抛出的确切时间点。


3
你可以这样做来分离延迟执行的部分(包含 yield 语句,会生成一个迭代器),并在赋值时执行你的检查。
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);
        }
    }
}

当异常被触发时(因为您的Count() == 3),您的catch将被调用,并且您的“result”将不会被设置。因此,当for循环尝试迭代结果时,它将是null。您需要添加一个null检查。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接