Cam*_*and 368 .net c# vb.net extension-methods
受到另一个询问失踪问题的启发 Zip功能的:
为什么课堂上没有ForEach扩展方法Enumerable?还是在任 唯一获得ForEach方法的类是List<>.有没有理由错过(表演)?
Coi*_*oin 189
在大多数情况下,该语言中已包含一个foreach语句.
我不想看到以下内容:
list.ForEach( item =>
{
item.DoSomething();
} );
Run Code Online (Sandbox Code Playgroud)
代替:
foreach(Item item in list)
{
item.DoSomething();
}
Run Code Online (Sandbox Code Playgroud)
在大多数情况下,后者更清晰,更容易阅读,但输入可能要长一些.
但是,我必须承认我在这个问题上改变了立场; 在某些情况下,ForEach()扩展方法确实很有用.
以下是语句和方法之间的主要区别:
这些都是很多人在这里提出的很好的观点,我可以看出为什么人们会错过这个功能.我不介意微软在下一个框架迭代中添加标准的ForEach方法.
aku*_*aku 73
在LINQ之前添加了ForEach方法.如果添加ForEach扩展,由于扩展方法约束,它将永远不会为List实例调用.我认为没有添加它的原因是不干扰现有的.
但是,如果你真的错过这个小功能,你可以推出自己的版本
public static void ForEach<T>(
this IEnumerable<T> source,
Action<T> action)
{
foreach (T element in source)
action(element);
}
Run Code Online (Sandbox Code Playgroud)
Jay*_*uzi 51
你可以编写这个扩展方法:
// Possibly call this "Do"
IEnumerable<T> Apply<T> (this IEnumerable<T> source, Action<T> action)
{
foreach (var e in source)
{
action(e);
yield return e;
}
}
Run Code Online (Sandbox Code Playgroud)
优点
允许链接:
MySequence
.Apply(...)
.Apply(...)
.Apply(...);
Run Code Online (Sandbox Code Playgroud)
缺点
在你做一些强制迭代之前,它实际上不会做任何事情.因此,不应该调用它.ForEach().您可以.ToList()在最后编写,或者您也可以编写此扩展方法:
// possibly call this "Realize"
IEnumerable<T> Done<T> (this IEnumerable<T> source)
{
foreach (var e in source)
{
// do nothing
;
}
return source;
}
Run Code Online (Sandbox Code Playgroud)
这可能与运输C#库有太大不同; 不熟悉您的扩展方法的读者将不知道您的代码是什么.
man*_*aus 33
这里的讨论给出了答案:
实际上,我目睹的具体讨论实际上取决于功能纯度.在表达式中,经常假设没有副作用.拥有ForEach是特别邀请副作用,而不仅仅是忍受它们. - Keith Farmer(合伙人)
基本上,决定保持扩展方法在功能上"纯粹".当使用Enumerable扩展方法时,ForEach会鼓励副作用,这不是意图.
Chr*_*ryk 17
虽然我同意foreach在大多数情况下使用内置构造更好,但我发现在ForEach <>扩展中使用这种变体比在常规中foreach自己管理索引要好一些:
public static int ForEach<T>(this IEnumerable<T> list, Action<int, T> action)
{
if (action == null) throw new ArgumentNullException("action");
var index = 0;
foreach (var elem in list)
action(index++, elem);
return index;
}
Run Code Online (Sandbox Code Playgroud)
例
var people = new[] { "Moe", "Curly", "Larry" };
people.ForEach((i, p) => Console.WriteLine("Person #{0} is {1}", i, p));
Run Code Online (Sandbox Code Playgroud)
会给你:
Person #0 is Moe
Person #1 is Curly
Person #2 is Larry
Run Code Online (Sandbox Code Playgroud)
Jay*_*uzi 14
一个解决方法是写.ToList().ForEach(x => ...).
利弊
易于理解 - 读者只需知道C#附带的内容,而不是任何其他扩展方法.
句法噪音非常温和(只增加了一些极端的代码).
通常不会花费额外的内存,因为本地人.ForEach()无论如何都必须实现整个集合.
缺点
操作顺序并不理想.我宁愿意识到一个元素,然后采取行动,然后重复.此代码首先实现所有元素,然后依次对它们进行操作.
如果实现列表抛出异常,则永远不会对单个元素执行操作.
如果枚举是无限的(就像自然数字一样),那你运气不好.
Aar*_*ell 13
我一直想知道自己,这就是为什么我总是随身携带这个:
public static void ForEach<T>(this IEnumerable<T> col, Action<T> action)
{
if (action == null)
{
throw new ArgumentNullException("action");
}
foreach (var item in col)
{
action(item);
}
}
Run Code Online (Sandbox Code Playgroud)
不错的小扩展方法.
因此,有很多关于ForEach扩展方法不合适的事实的评论,因为它不返回类似LINQ扩展方法的值.虽然这是一个事实陈述,但并非完全正确.
LINQ扩展方法都返回一个值,以便它们可以链接在一起:
collection.Where(i => i.Name = "hello").Select(i => i.FullName);
Run Code Online (Sandbox Code Playgroud)
但是,仅仅因为使用扩展方法实现LINQ并不意味着必须以相同的方式使用扩展方法并返回值.编写扩展方法以公开不返回值的常用功能是完全有效的用法.
关于ForEach的具体论点是,基于对扩展方法的约束(即扩展方法永远不会覆盖具有相同签名的继承方法),可能存在这样一种情况:自定义扩展方法在所有可用的类上都可用IEnumerable <T>除了List <T>.当方法开始表现不同时,这可能会导致混淆,具体取决于是否调用了扩展方法或继承方法.
您可以使用(可链接但经过懒惰评估)Select,首先执行操作,然后返回标识(如果您愿意,还可以返回其他内容)
IEnumerable<string> people = new List<string>(){"alica", "bob", "john", "pete"};
people.Select(p => { Console.WriteLine(p); return p; });
Run Code Online (Sandbox Code Playgroud)
你需要确保它仍然被评估,无论Count()是最简单的操作(枚举afaik)还是你需要的其他操作.
我很乐意看到它带入标准库:
static IEnumerable<T> WithLazySideEffect(this IEnumerable<T> src, Action<T> action) {
return src.Select(i => { action(i); return i; } );
}
Run Code Online (Sandbox Code Playgroud)
然后上面的代码变得people.WithLazySideEffect(p => Console.WriteLine(p))有效地等同于foreach,但是懒惰和可链接.
注意,MoreLINQ NuGet提供了ForEach您要查找的扩展方法(以及Pipe执行委托并产生其结果的方法)。看到:
| 归档时间: |
|
| 查看次数: |
138107 次 |
| 最近记录: |