Reputation: 1937
I have an overrided SaveChangesAsync
EF method as following:
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
{
ChangeTracker
.Entries()
.Where(e => e.State == EntityState.Added)
.Select(e => e.Entity as BaseEntity)
.ForEach(e => e.ModifiedOn = e.CreatedOn = DateTimeOffset.Now);
return base.SaveChangesAsync(cancellationToken);
}
BaseEntity
is also my class with some common properties like CreatedOn
and every entity inherits from this class. This overrided method uses my own ForEach
extension:
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
{
foreach (var item in enumerable)
{
action(item);
yield return item;
}
}
And the foreach loop is not executing when there is a yield statement. If I change it to this:
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
{
foreach (var item in enumerable)
{
action(item);
}
return enumerable;
}
Then it works perfectly. Why does yield is not executing it this iteration?
Upvotes: 0
Views: 1410
Reputation: 3498
If you use yield return
or yield break
your code will only be executed if someone iterates over the IEnumerable<T>
you get from the function.
The yield
operator makes it possible to write lazy code.
Append .ToList()
or .ToArray()
to the statement, but I recommend .ToList()
, because .ToArray()
needs to create multiple arrays if the argument is not of the type ICollection<T>
.
See
Upvotes: 1
Reputation: 42639
Deferred execution. The code is executed at the time when you consume the yielded items, eg. by looping over the result or by calling .ToList()
on it. In your code example it seems like you never consume the result of the iteration, so it is never executed.
Upvotes: 5
Reputation: 81493
Because an iterator needs to iterate
Call ToList();
You use a yield return statement to return each element one at a time.
You consume an iterator method by using a foreach statement or LINQ query. Each iteration of the foreach loop calls the iterator method. When a yield return statement is reached in the iterator method, expression is returned, and the current location in code is retained. Execution is restarted from that location the next time that the iterator function is called.
In short
The call to ForEach
doesn't execute the body of the method. Instead the call returns an IEnumerable, Since nothing enumerates over it, the method doesn't even hit the body at all as it has never started iterating.
Upvotes: 2