正确检查论点

在枚举返回值之前,不会执行迭代器方法。因此,在迭代器之外断言前置条件是有利的。

public static IEnumerable<int> Count(int start, int count)
{
    // The exception will throw when the method is called, not when the result is iterated
    if (count < 0)
        throw new ArgumentOutOfRangeException(nameof(count));

    return CountCore(start, count);
}

private static IEnumerable<int> CountCore(int start, int count)
{
    // If the exception was thrown here it would be raised during the first MoveNext()
    // call on the IEnumerator, potentially at a point in the code far away from where
    // an incorrect value was passed.
    for (int i = 0; i < count; i++)
    {
        yield return start + i;
    }
}

呼叫侧码(用法):

// Get the count
var count = Count(1,10);
// Iterate the results
foreach(var x in count)
{
    Console.WriteLine(x);
}

输出:

1
2
3
4
5
6
7
8
9
10

.NET 小提琴现场演示

当方法使用 yield 生成可枚举时,编译器会创建一个状态机,当迭代时将运行代码到 yield。然后它返回生成的项目,并保存其状态。

这意味着当你第一次调用方法(因为它创建状态机)时,你不会发现有关无效参数(传递 null 等),只有当你尝试访问第一个元素时(因为只有这样才能在方法由状态机运行)。通过将其包装在首先检查参数的常规方法中,你可以在调用方法时检查它们。这是快速失败的一个例子。

使用 C#7+时,CountCore 函数可以方便地作为局部函数隐藏在 Count 函数中。见这里的例子。