List <T> .ForEach与自定义IEnumerable <T>扩展名

Kla*_*sen 4 c# linq extension-methods

说我有一节课:

public class MyClass
{
   ...
}
Run Code Online (Sandbox Code Playgroud)

和一个返回的Web服务方法 IEnumerable<MyClass>

Web服务的使用者定义了一些方法:

public void DoSomething(MyClass myClass)
{
   ...
}
Run Code Online (Sandbox Code Playgroud)

现在,消费者可以DoSomething通过两种方式调用webservice方法的结果:

var result = // web service call

foreach(var myClass in result)
{
   DoSomething(myClass);
}
Run Code Online (Sandbox Code Playgroud)

要么:

var result = // web service call

result.ToList().ForEach(DoSomething);
Run Code Online (Sandbox Code Playgroud)

毋庸置疑,我更喜欢第二种方式,因为它更短,更具表现力(一旦你习惯了我的语法).

现在,Web服务方法只公开一个IEnumerable<MyClass>,但它实际上返回一个List<MyClass>(AFAIK)意味着实际的序列化对象仍然是一个List<T>.但是,我发现(使用反射器)Linq方法ToList()制作了所有对象的副本,IEnumerable<T>而不管实际的运行时类型(在我看来,它可能只是将参数转换为a,List<T>如果它已经是一个).

这显然有一些性能开销,特别是对于大型列表(或大型对象列表).

那么我该怎么做才能克服这个问题,为什么ForEachLinq中没有方法呢?

顺便说一句,他的问题与这个问题含糊不清.

Jam*_*Ide 5

您可以编写扩展方法,但有充分的理由说明为什么没有实现ForEach IEnumerable<T>.第二个例子

result.ToList().ForEach(DoSomething);
Run Code Online (Sandbox Code Playgroud)

将IEnumerable复制到List中(除非它已经是List,我假设)所以你最好只用旧的迭代IEnumerable foreach(var r in result) {}.

附录:

对我来说,Eric Lippert的文章的关键点是添加ForEach没有任何好处,并增加了一些潜在的陷阱:

第二个原因是,这样做会增加语言的新代表性能力.这样做可以让你重写这个完全清晰的代码:

foreach(foo foo in foos){声明涉及foo; }

进入这段代码:

foos.ForEach((Foo foo)=> {声明涉及foo;});

它使用几乎完全相同的字符,顺序略有不同.然而第二个版本更难理解,更难调试,并引入了闭包语义,从而可能以微妙的方式改变对象的生命周期.


Ant*_*nes 5

我更喜欢这个: -

foreach (var item in result.ToList())
{
   DoSomething(item);
}
Run Code Online (Sandbox Code Playgroud)

它是一个更清晰的习语,它说收集一起列表的东西,然后做一些重要的事情,可能会改变应用程序的状态.它的旧学校,但它的工作,实际上更广泛的观众可以理解.