问题
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?
回答1:
A single method cannot both yield return
and return
. You must choose one or the other.
You can either do a foreach
to yield return
the list:
else
{
foreach (var item in CalculateDeltas(sequence))
yield return item;
}
Or separate your code into two methods:
if (absolute)
return CalculateAbsoluteDeltas(sequence);
else
return CalculateDeltas(sequence);
回答2:
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.
来源:https://stackoverflow.com/questions/23391119/error-iterator-cannot-contain-return-statement-when-calling-a-method-that-ret