Is there really multiple iterations of an IEnumerable in this code? - c#

public static IEnumerable<T> ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var element in source) action(element);
return source;
}
The code above gives me a warning that source is potentially iterated multiple times, but is it really? It's iterated once in the foreach statement, but how does the return statement make it iterated again?

The return doesn't iterate the enumerable again. But you are returning it, and since the only way you could possibly do ANYTHING with this result is to iterate it elsewhere, this warning is given.
Why return it if you are not going to iterate it later?

In the current code you show there is only one iteration. It is very well possible that you are enumerating it again somewhere else since the same enumerable is returned. That is what the warning is telling you.
My personal preference would be to change the return type of the ForEach to void, and add a second one that returns the result of a Func<T, R>.
So:
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var element in source)
action(element);
}
And:
public static IEnumerable<R> ForEach<T, R>(this IEnumerable<T> source, Func<T, R> action)
{
foreach (var element in source)
yield return action(element);
}
That way you are never accidentally reusing the same enumerable and you are making it lazy: it won't execute before you actually call the enumerable.

Related

LINQ Select - CS0411 The type arguments cannot be inferred from the usage - What am I doing wrong?

Goal: ForEach extension masking Select.
Reason: Select allows for method chaining while foreach does not; ForEach is more readable than Select.
The problem I'm running into is that I'm getting this error.
The type arguments for method 'System.Linq.Enumerable.Select(System.Collections.Generic.IEnumerable, System.Func)' cannot be inferred from the usage. Try specifying the type arguments explicitly. (CS0411)
public static void ForEach<T>(this IEnumerable<T> elements, Action<T, int> action)
{
elements.Select((elem, i) => action(elem, i));
}
I've tried doing elements.Select((T elem, int i) => action(elem, i)); but that produces the same error.
I've also attempted using Func instead of Action but there doesn't seem to be any way to use void for the return (which is what Action is for anyways). If I define the method to take a Func instead of Action then when I try to call it using Action I get the same error.
public static IEnumerable<TOut> ForEach<TIn, TOut>(this IEnumerable<TIn> elements,
Func<TIn, int, TOut> function)
{
return elements.Select((elem, i) => function(elem, i))
.ToList();
}
I don't understand which arguments cannot be inferred. There are ways I could get around this (using a for loop or foreach loop and track the index), but I would still like to figure out why this won't work.
Edit: I also just realized my other ForEach for Action (no index) also gets this error when I switch from a foreach loop to calling Select.
public static void ForEach<T>(this IEnumerable<T> elements, Action<T> action)
{
elements.ToList().Select((T elem) => action(elem));
/*foreach (var elem in elements)
action(elem);*/
}
The problem is that Select expects a return value (you're projecting an object into something else) - of which your Action is returning void. void can't be converted into T, which is what Select is expecting.
The simple fix is to ensure something is returned at the end of your select function:
public static void ForEach<T>(this IEnumerable<T> elements, Action<T, int> action)
{
elements.Select((elem, i) =>
{
action(elem, i);
return elem;
}).Count();
}
The action is called, and the collection continues to be enumerated. We need to call Count because nothing will actually happen until we attempt to get a value from each enumeration (thank you Jon Skeet!)
Note that this isn't how Select should be used - the OP specifically asked why/how to make it work with it.
To do this properly, as mentioned in the comments, the solution is to use an actual foreach loop with a counter:
public static void ForEach<T>(this IEnumerable<T> elements, Action<T, int> action)
{
int count = 0;
foreach (var item in elements)
{
action(item, count++);
}
}
If you want to allow method chaining, you can do it this way:
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> elements, Action<T, int> action)
{
int count = 0;
foreach (var item in elements)
{
action(item, count++);
yield return item;
}
}

How can I get a list of CollectionBase items?

In C#, if I have a CollectionBase of type T, and each item in the CollectionBase can have a child CollectionBase of the same type T, how can I get a list of all type T objects without using a recursive function?
Does LINQ have a feature to do this?
Thanks in advance.
Wes Dyer wrote actually a nice topic on this, have a look.
As for your case I think you would need an iterator, probably something like this:
public static IEnumerable<T> Flatten<T>(this IEnumerable<T> e, Func<T,IEnumerable<T>> f)
{
return e.SelectMany(c => f(c).Flatten(f)).Concat(e);
}
This is answer is taken from here.
EDIT: I just remember that you can also traverse the tree.
public static IEnumerable<T> Traverse<T>(T item, Func<T, IEnumerable<T>> childSelector)
{
var stack = new Stack<T>();
stack.Push(item);
while (stack.Any())
{
var next = stack.Pop();
yield return next;
foreach (var child in childSelector(next))
stack.Push(child);
}
}

Difference between LINQ FirstOrDefault vs. Where(...).FirstOrDefault?

What difference between
FirstOrDefault(someField => someField.Name.Equals(settings.Text))
and
Where(someField => someField.Name.Equals(settings.Text)).FirstOrDefault()
?
As far as I understand in both cases Linq will run till the first occurence that suits the condition.
They result of both statements is the same. You can think of the first one as a shorter version of the second one.
The FirstOrDefault method has an overload taking in a second parameter, a Func<TSource, bool> which is the same predicate you are defining in your Where statement.
If we are talking about Linq to Objects, then there is one notable difference. Second statement
Where(someField => someField.Name.Equals(settings.Text)).FirstOrDefault()
Will create WhereEnumerableIterator internally, and then it will start enumeration and take first item:
// argument checks and collection optimizations removed
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
// it enumerates source and returns items which match predicate
return new WhereEnumerableIterator<TSource>(source, predicate);
}
public static TSource First<TSource>(this IEnumerable<TSource> source)
{
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (enumerator.MoveNext())
return enumerator.Current;
}
throw Error.NoElements();
}
But first statement will just take first item from source which matches predicate without creating additional enumerator:
// argument checks removed
public static TSource First<TSource>(
this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
foreach (TSource local in source)
{
if (predicate(local))
return local;
}
throw Error.NoMatch();
}
So, first one is better in terms of performance:
FirstOrDefault(someField => someField.Name.Equals(settings.Text))

How does Concat() actually join the collections at lower level?

What is Linq actually doing?
(I'm assuming this is for LINQ to Objects. Anything else will be implemented differently :)
It's just returning everything from the first, and then everything from the second. All data is streamed. Something like this:
public static IEnumerable<T> Concat(this IEnumerable<T> source1,
IEnumerable<T> source2)
{
if (source1 == null)
{
throw new ArgumentNullException("source1");
}
if (source2 == null)
{
throw new ArgumentNullException("source1");
}
return ConcatImpl(source1, source2);
}
private static IEnumerable<T> ConcatImpl(this IEnumerable<T> source1,
IEnumerable<T> source2)
{
foreach (T item in source1)
{
yield return item;
}
foreach (T item in source2)
{
yield return item;
}
}
I've split this into two methods so that the argument validation can be performed eagerly but I can still use an iterator block. (No code within an iterator block is executed until the first call to MoveNext() on the result.)
It enumerates each collection in turn, and yields each element. Something like that :
public static IEnumerable<T> Concat<T>(this IEnumerable<T> source, IEnumerable<T> other)
{
foreach(var item in source) yield return item;
foreach(var item in other) yield return item;
}
(if you look at the actual implementation using Reflector, you will see that the iterator is actually implemented in a separate method)
It depends on the LINQ provider you are using. LinqToSql or L2E might use a database UNION, whereas LINQ to Objects might just enumerate both collections for your in turn.

A different take on FirstOrDefault

The IEnumerable extension method FirstOrDefault didn't exactly do as I wanted so I created FirstOrValue. Is this a good way to go about this or is there a better way?
public static T FirstOrValue<T>(this IEnumerable<T> source, Func<T, bool> predicate, T value)
{
T first = source.FirstOrDefault(predicate);
return Equals(first, default(T)) ? value : first;
}
Your code is probably incorrect; you probably haven't considered all of the cases.
Of course, we cannot know if any code is correct or incorrect until we have a spec. So start by writing a one-line spec:
"FirstOrValue<T> takes a sequence of T, a predicate, and a value of T, and returns either the first item in the sequence that matches the predicate if there is one, or, if there is not, the stated value."
Does your attempt actually implement that spec? Certainly not! Test it:
int x = FirstOrValue<int>( new[] { -2, 0, 1 }, y=>y*y==y, -1);
this returns -1. The correct answer according to the spec is 0. The first item that matches the predicate is zero, so it should be returned.
A correct implementation of the spec would look like:
public static T FirstOrValue<T>(this IEnumerable<T> sequence, Func<T, bool> predicate, T value)
{
if (sequence == null) throw new ArgumentNullException("sequence");
if (predicate == null) throw new ArgumentNullException("predicate");
foreach(T item in sequence)
if (predicate(item)) return item;
return value;
}
Always write a spec first, even if it's only a single sentence.
default(T) will return null by default for reference types.
I would do this
public static T FirstOrValue<T>(this IEnumerable<T> source, Func<T, bool> predicate, T value)
{
T first = source.FirstOrDefault(predicate);
return first ?? value;
}
Since this is an overload, it's worth mentioning the version with no predicate.
public static T FirstOrValue<T>(this IEnumerable<T> sequence, T value)
{
if (sequence == null) throw new ArgumentNullException("sequence");
foreach(T item in sequence)
return item;
return value;
}
Seems reasonable to me if you want to tweak the readability instead of using DefaultIfEmpty.
You could also create an override that uses a lambda if the creation of the default value is expensive, creating it only if necessary.
public static T FirstOrValue<T>(this IEnumerable<T> source, Func<T, bool> predicate, Func<T> getValue)
{
T first = source.FirstOrDefault(predicate);
return Equals(first, default(T)) ? getValue() : first;
}

Categories