调用使用yield返回的方法时出现“迭代器不能包含return语句”的错误

17

我希望有一种更好的方法来编写这个方法和重载,以减少代码复制。 我想返回列表项之间的增量序列。 这是该方法:

    public static IEnumerable<decimal> CalculateDeltas(this IEnumerable<decimal> sequence)
    {
        decimal prev = default(decimal);
        foreach (var item in sequence)
        {
            var current = item;
            decimal diff = current - prev;
            prev = item;
            yield return diff;
        }
    }

运作得非常好。

然后我考虑了一种重载方式,它可以允许使用绝对值的偏移量,但如果不需要绝对值,则会调用原始方法:

    public static IEnumerable<decimal> CalculateDeltas(this IEnumerable<decimal> sequence,bool absolute)
    {
        if (absolute)
        {
            decimal prev = default(decimal);
            foreach (var item in sequence)
            {
                var current = item;
                decimal diff = Math.Abs(current - prev);
                prev = item;
                yield return diff;
            }
        }
        else
        {
            return CalculateDeltas(sequence);
        }
    }

但是因为错误,这段代码无法编译。

"无法从迭代器返回值。使用yield return语句返回值,或使用yield break结束迭代。"

我查看了这篇帖子,似乎我只能重复原始方法中的代码而无法做其他事情:

    public static IEnumerable<decimal> CalculateDeltas(this IEnumerable<decimal> sequence,bool absolute)
    {
        if (absolute)
        {
            decimal prev = default(decimal);
            foreach (var item in sequence)
            {
                var current = item;
                decimal diff = Math.Abs(current - prev);
                prev = item;
                yield return diff;
            }
        }
        else
        {
            decimal prev = default(decimal);
            foreach (var item in sequence)
            {
                var current = item;
                decimal diff = current - prev;
                prev = item;
                yield return diff;
            }
        }
    }

有人能建议更好的做法吗?

2个回答

26

一个方法不能同时使用yield returnreturn。你必须选择其中一个。

你可以使用foreach循环来yield return列表:

else
{
    foreach (var item in CalculateDeltas(sequence))
        yield return item;
}

或者将你的代码分成两个方法:

if (absolute)
    return CalculateAbsoluteDeltas(sequence);
else
    return CalculateDeltas(sequence);

谢谢你的回复,Tim。我真的很希望你的第一种方法能够奏效,但它无法编译:错误:无法隐式转换类型'System.Collections.Generic.IEnumerable<decimal>'到'decimal'。 - Dave00Galloway
@Dave00Galloway 哦,我在 yield return 后面放错了东西。用 item 试试(我刚刚编辑了我的答案)。 - Tim S.
S - 谢谢,这个很好用。我更喜欢使用 _yield return item;_,因为它避免了编写额外方法的麻烦,所以你刚刚从Jon Skeet那里“偷走”了这个“答案”! - Dave00Galloway
这也能工作,因为原始方法是一个扩展方法:- foreach (var item in sequence.CalculateDeltas()) yield return item; - Dave00Galloway

4
最简单的方法可能是将方法分为两部分,一部分通过迭代器块实现,另一部分则不是:
public static IEnumerable<decimal> CalculateDeltas(this IEnumerable<decimal> sequence,
                                                   bool absolute)
{
    return absolute ? CalculateAbsoluteDeltas(sequence) 
                    : CalculateDeltas(sequence);
}

private static IEnumerable<decimal> CalculateAbsoluteDeltas
    (IEnumerable<decimal> sequence)
{
    decimal prev = default(decimal);
    foreach (var item in sequence)
    {
        var current = item;
        decimal diff = Math.Abs(current - prev);
        prev = item;
        yield return diff;
    }
}

这种分离的方法还可以让您急切地验证代码中的 sequence,例如:
if (sequence == null) {
    throw new ArgumentNullException("sequence");
}

在非迭代器块方法中。

除了 IEnmuable 上的拼写错误 :) - Dave00Galloway

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