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?
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:
This split approach also allows you to eagerly validate
sequence
, e.g.... in the non-iterator block method.
A single method cannot both
yield return
andreturn
. You must choose one or the other.You can either do a
foreach
toyield return
the list:Or separate your code into two methods: