List <T> .ForEach vs. IEnumerable <T> Custom Extension

Say I have a class:

public class MyClass { ... } 

and a webservice method that returns IEnumerable<MyClass>

A web service consumer defines a method:

 public void DoSomething(MyClass myClass) { ... } 

Now the consumer can call DoSomething according to the result of the webservice method in two ways:

 var result = // web service call foreach(var myClass in result) { DoSomething(myClass); } 

or

 var result = // web service call result.ToList().ForEach(DoSomething); 

Needless to say, I prefer the second way, because it is much shorter and more expressive (as soon as you get used to the syntax that I have).

Now the web service method provides only IEnumerable<MyClass> , but actually returns a List<MyClass> , which (AFAIK) means that the actual serialized object is still List<T> . However, I found (using a reflector) that the Linq ToList() method makes a copy of all objects in IEnumerable<T> regardless of the actual type of runtime (in my opinion, it could just pass an argument if it was already one).

This obviously has some overhead, especially for a large list (or lists of large objects).

So, what can I do to overcome this problem and why there is no ForEach method in Linq

By the way, his question is vaguely related to this .

+4
source share
6 answers

I use 2 methods. One iteration of the list, one works with lazy eval. I use them depending on the situation.

  public static IEnumerable<T> ForEachChained<T>(this IEnumerable<T> source, Action<T> action) { foreach (var item in source) { action(item); yield return item; } } public static IEnumerable<T> ForEachImmediate<T>(this IEnumerable<T> source, Action<T> action) { foreach (var item in source) { action(item); } return source; } 
+4
source

You can write an extension method, but there are good reasons why ForEach is not implemented on IEnumerable<T> . Second example

 result.ToList().ForEach(DoSomething); 

copies IEnumerable to the list (if I'm not already a list, I suppose), so you'd better just repeat IEnumerable with the good old foreach(var r in result) {} .

Application:

For me, the key point of Eric Lippert's article is that adding ForEach has no advantages and adds some potential traps:

The second reason is that it adds zero new representative power to the language. This allows you to rewrite this perfectly understandable code:

foreach (Foo foo in foos) {statement involving foo; }

in this code:

foos.ForEach ((Foo foo) => {statement involving foo;});

which uses almost the same characters in a slightly different order. Nevertheless, the second version is more difficult to understand, more difficult to debug, and introduces the semantics of closure, thereby potentially changing the object of life in subtle directions.

+5
source

I would prefer this: -

 foreach (var item in result.ToList()) { DoSomething(item); } 

His clearer idiom, he says, puts a list of things together and then does something important that can change the state of the application. His is an old school, but it works and is actually more understandable to a wide audience.

+5
source

You can write your own extension method for IEnumerable<T> as follows:

  public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action) { foreach (T t in enumerable) action(t); } 

This method is not available in Linq, because Linq is mainly intended for queries, and not for simple iterations.

Also note that when using an actual instance of List<T> the extension method will not be called because the instance methods take precedence over extension methods when they share the signature.

The following code, for example, will not call the extension method:

  var l = new List<MyClass>(); l.Add(new MyClass()); l.ForEach(DoSomething); 

While the following:

 IEnumerable<MyClass> l = new List<MyClass>(new []{new MyClass()}); l.ForEach(DoSomething); 
+2
source

You can write your own ToList extension method (this theList list) {return theList;}, and then avoid the overhead. Since your extension method is the most specific, it will be called, not the one that is in IEnumerable

+1
source

If you decide to do this using the extension method, I would call it ForAll instead of ForEach. This is to use the same syntax as Parallel Extensions in .NET 4.0 :

 var result = // web service call result.AsParallel().ForAll(DoSomething); 
-2
source

Source: https://habr.com/ru/post/1301843/


All Articles