收益率和异常处理[重复]

问题描述 投票:3回答:1

这个问题在这里已有答案:

我刚才有一个使用yield返回的方法没有抛出我期望的ArgumentException的情况。我在这里用最简单的可能类重构了这个案例:

class Program
{
    static void Main(string[] args)
    {
        try
        {
            var listA = FooA(count: 0);
            Console.WriteLine("A did not throw exception!");
        }
        catch (ArgumentException)
        {
            Console.WriteLine("A threw exception!");
        }

        try
        {
            var listB = FooB(count: 0);
            Console.WriteLine("B did not throw exception!");
        }
        catch (ArgumentException)
        {
            Console.WriteLine("B threw exception!");
        }

        Console.ReadLine();
    }

    private static IEnumerable<int> FooA(int count)
    {
        if(count == 0)
            throw new ArgumentException("Count must be above 0");
        var list = new List<int>();
        for (var i = 0; i < count; i++)
        {
            list.Add(i);
        }
        return list;
    }

    private static IEnumerable<int> FooB(int count)
    {
        if (count == 0)
            throw new ArgumentException("Count must be above 0");
        for (var i = 0; i < count; i++)
        {
            yield return i;
        }
    }
}

输出:

A threw exception!
B did not throw exception!

有人可以向我解释为什么FooB在FooA没有抛出异常的原因吗?

c# exception clr jit yield-return
1个回答
7
投票

这是因为FooB甚至从未被评估过。

调用方法时,会立即调用该方法。当你使用yield并返回一个枚举时,只有当某些东西需要使用返回的值时才会调用该方法,并且一次只能使用一个项目;这是yielding的好处。

所以,如果你添加一些使用该值的东西

try
{
    var listB = FooB(count: 0);
    Console.WriteLine(listB.First()); // use the IEnumerable returned
    Console.WriteLine("B did not throw exception!");
}
catch (ArgumentException)
{
    Console.WriteLine("B threw exception!");
}

您将看到预期的结果。

© www.soinside.com 2019 - 2024. All rights reserved.