Examples:
public IEnumerable<Class> ReturnClass()
{
var list = ...;
return list.Select(item =>
{
// if, else, etc
return item;
});
}
or
public IEnumerable<Class> ReturnClass()
{
var list = ...;
foreach (var item in list)
{
// if, else, etc
yield return item;
}
}
Are there differences in the generated code? Performance? Etc
I only found one question on stackoverflow about this subject, but it raised more questions than it answered questions
The main differences is that yield return
creates state machine and thus executes lazily. Lazy execution can be problematic in case of validation, let me show some toy example:
// State Machine, Lazy execution
public IEnumerable<int> ReturnClassLazy(int count)
{
// Validation (will be called lazily)
if (count < 0)
throw new ArgumentOutOfRangeException(nameof(count));
var list = Enumerable.Range(1, count);
foreach (var item in list)
yield return item * item;
}
// Eager execution
public IEnumerable<int> ReturnClassEager(int count)
{
// Validation (will be called eagerly)
if (count < 0)
throw new ArgumentOutOfRangeException(nameof(count));
var list = Enumerable.Range(1, count);
return list.Select(item => item * item);
}
In case of eager version (when we return Select(...)
), the method will be executed immediately (note, that validation will be called):
// ArgumentOutOfRangeException is thrown (invalid count argument, -1)
var result = ReturnClassEager(-1);
while in case of lazy call (yield return
version)
// Nothing happens (even if count argument -1 is invalid)
var result = ReturnClassLazy(-1);
... /* imagine 10000 lines of code here */
// Only here (when we materialize)
// the exception is thrown due to invalid count argument -1
int sum = result.Sum();
Usually, we want validation exception be thrown as early as possible, that's why eager version is easier to maintain.