List<T>
有一个调用的方法ForEach
,它对每个元素执行传递的操作.
var names = new List<String>{ "Bruce", "Alfred", "Tim", "Richard" };
names.ForEach(p => { Console.WriteLine(p); });
Run Code Online (Sandbox Code Playgroud)
但是,如果names
不是一个List<T>
但是IList<T>
,IList<T>
没有像这样的方法ForEach
.还有其他选择吗?
O. *_*per 42
使用foreach
循环:
foreach (var p in names) {
Console.WriteLine(p);
}
Run Code Online (Sandbox Code Playgroud)
如果这实际上没有提高可读性,则没有理由在整个地方使用委托和扩展方法; 一个foreach
循环并没有明确地告诉读者正在做什么而不是一个ForEach
方法.
naw*_*fal 21
如果你IList<T>
是一个数组(T[]
),那么你就有类似于on的Array.ForEach方法.您可以创建自定义的扩展方法或或任何你喜欢的.ForEach
List<T>
IList<T>
IEnumerable<T>
public static void ForEach<T>(this IList<T> list, Action<T> action)
{
foreach (T t in list)
action(t);
}
Run Code Online (Sandbox Code Playgroud)
你只需要警惕原始集合中的对象将被修改的事实,但我想命名确实暗示了这一点.
-------------------------------------------------- -------------------------------------------------- --------------------------------
我更喜欢打电话:
people.Where(p => p.Tenure > 5)
.Select(p => p.Nationality)
.ForEach(n => AssignCitizenShip(n);
Run Code Online (Sandbox Code Playgroud)
比
foreach (var n in people.Where(p => p.Tenure > 5).Select(p => p.Nationality))
{
AssignCitizenShip(n);
}
Run Code Online (Sandbox Code Playgroud)
如果是这样,您可以创建扩展方法IEnumerable
.请注意,终止呼叫会ForEach
执行Linq
查询.如果你不想要它,你也可以通过使用yield
语句并返回一个来推迟它IEnumerable<T>
:
public static IEnumerable<T> ForEach<T>(this IEnumerable<T> list, Action<T> action)
{
foreach (T t in list)
{
action(t);
yield return t;
}
}
Run Code Online (Sandbox Code Playgroud)
这解决了副作用问题,但我个人喜欢一个名为ForEach
最终执行调用的方法.
-------------------------------------------------- -------------------------------------------------- -------------------------------
为了解决喜好的反对意见,这里是一个更好的链路从埃里克利珀比这个.引用他:
"第一个原因是这样做违反了所有其他序列操作符所依据的函数式编程原则.显然,调用此方法的唯一目的是引起副作用.表达式的目的是计算一个值,不要引起副作用.声明的目的是引起副作用.这个东西的调用网站看起来很像一个表达式(但是,诚然,因为该方法是无效的返回,表达式只能可以在"语句表达式"上下文中使用.)我不能很好地创建唯一对其副作用有用的序列运算符.
第二个原因是,这样做会增加语言的新代表性能力".
埃里克并没有说这是件坏事 - 只是决定不在默认情况下包含构造的哲学原因Linq
.如果您认为某个函数不IEnumerable
应该对内容起作用,那么就不要这样做.就个人而言,我不介意,因为我很清楚它的作用.我将其视为导致集合类副作用的任何其他方法.如果我愿意的话,我也可以进入函数并调试它.这是另一个Linq
自己.
people.Where(p => p.Tenure > 5)
.Select(p => p.Nationality)
.AsParallel()
.ForAll(n => AssignCitizenShip(n);
Run Code Online (Sandbox Code Playgroud)
正如我所说,这些并没有什么不好.它只是个人喜好.我不会将它用于嵌套foreach
s,或者它是否涉及在foreach
循环内部执行多行代码,因为这是不可读的.但是对于我发布的简单示例,我喜欢它.看起来干净简洁.
编辑:请参阅性能链接btw:为什么List <T> .ForEach比标准foreach更快?
您可以制作扩展方法并使用大部分实现void List<T>.ForEach(Action<T> action)
.您可以在Shared Source Initiative站点下载源代码.
基本上你会结束这样的事情:
public static void ForEach<T>(this IList<T> list, Action<T> action)
{
if (list == null) throw new ArgumentNullException("null");
if (action == null) throw new ArgumentNullException("action");
for (int i = 0; i < list.Count; i++)
{
action(list[i]);
}
}
Run Code Online (Sandbox Code Playgroud)
它比使用该foreach
语句的其他实现略胜一筹,因为它利用了IList包含索引器的事实.
虽然我对OR Mapper的答案很有帮助,但有时候在很多开发人员的大项目中,很难让每个人都认为foreach
声明更清晰.更糟糕的是,如果您的API基于接口(IList)而不是具体类型(List),那么习惯的开发人员List<T>.ForEach method
可能会开始调用ToList
您的IList引用!我知道,因为它发生在我之前的项目中.我按照框架设计指南在我们的公共API中使用集合接口.我花了一段时间注意到许多不习惯这种情况的开发人员ToList
开始以惊人的速度开始使用.最后,我将这个扩展方法添加到每个人都在使用的公共程序集中,并确保ToList
从代码库中删除所有不必要的调用.
归档时间: |
|
查看次数: |
43900 次 |
最近记录: |