立即返回所有可枚举,并返回收益;不循环

问题描述 投票:163回答:6

我具有以下功能来获取卡的验证错误。我的问题与处理GetErrors有关。两种方法具有相同的返回类型IEnumerable<ErrorInfo>

private static IEnumerable<ErrorInfo> GetErrors(Card card)
{
    var errors = GetMoreErrors(card);
    foreach (var e in errors)
        yield return e;

    // further yield returns for more validation errors
}

是否有可能在不必枚举它们的情况下返回GetMoreErrors中的所有错误?

考虑这可能是一个愚蠢的问题,但我想确保自己没有错。

c# ienumerable yield yield-return
6个回答
138
投票

这绝对不是一个愚蠢的问题,F#支持整个集合使用yield!,而单个项目使用yield。 (就尾递归而言,这可能非常有用...)

很遗憾,C#不支持。

但是,如果有几种方法每个都返回一个IEnumerable<ErrorInfo>,则可以使用Enumerable.Concat使代码更简单:

private static IEnumerable<ErrorInfo> GetErrors(Card card)
{
    return GetMoreErrors(card).Concat(GetOtherErrors())
                              .Concat(GetValidationErrors())
                              .Concat(AnyMoreErrors())
                              .Concat(ICantBelieveHowManyErrorsYouHave());
}

尽管这两种实现之间有一个非常重要的区别:即使每次只使用一个返回的迭代器,它也会立即调用所有方法。您的现有代码将一直等到它循环遍历GetMoreErrors()中的所有内容,然后甚至对下一个错误进行[[asks]。

通常这并不重要,但是值得了解何时会发生什么。

25
投票
您可以像这样设置所有错误源(方法名称是从Jon Skeet的答案中借来的。)>

private static IEnumerable<IEnumerable<ErrorInfo>> GetErrorSources(Card card) { yield return GetMoreErrors(card); yield return GetOtherErrors(); yield return GetValidationErrors(); yield return AnyMoreErrors(); yield return ICantBelieveHowManyErrorsYouHave(); }

然后您可以同时遍历它们。

private static IEnumerable<ErrorInfo> GetErrors(Card card) { foreach (var errorSource in GetErrorSources(card)) foreach (var error in errorSource) yield return error; }

或者,您也可以使用SelectMany展平错误源。

private static IEnumerable<ErrorInfo> GetErrors(Card card) { return GetErrorSources(card).SelectMany(e => e); }

GetErrorSources中方法的执行也会延迟。

14
投票
我想出了一个快速的yield_摘要:

8
投票

4
投票

3
投票
© www.soinside.com 2019 - 2024. All rights reserved.