Error 'Iterator cannot contain return statement ' when calling a method that returns using a yield

I'm hoping there's a nicer way to write this method & overloads with less code duplication. I want to return a sequence of deltas between items in a list. this method:-

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

works just fine.

I then thought about an overload which would allow an absolute delta, but would call the original method if absolute wasn't required:-

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

but this doesn't compile because of Error

"Cannot return a value from an iterator. Use the yield return statement to return a value, or yield break to end the iteration."

I've had a look at this post and it seems like I won't be able to do anything other than repeating the code from the original method:-

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

Can anyone suggest a better way of doing this?

Jon Skeet
people
quotationmark

The simplest approach is probably to split the method into two, one of which is implemented via an iterator block and one of which isn't:

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

This split approach also allows you to eagerly validate sequence, e.g.

if (sequence == null) {
    throw new ArgumentNullException("sequence");
}

... in the non-iterator block method.

people

See more on this question at Stackoverflow