C# 为什么 IEnumerable 上没有 ForEach 扩展方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/101265/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 14:04:17  来源:igfitidea点击:

Why there is no ForEach extension method on IEnumerable?

提问by Cameron MacFarland

Inspired by another question asking about the missing Zipfunction:

受到另一个询问缺失Zip函数的问题的启发:

Why is there no ForEachextension method in the Enumerableclass? Or anywhere? The only class that gets a ForEachmethod is List<>. Is there a reason why it's missing (performance)?

为什么类中没有ForEach扩展方法Enumerable?或者任何地方?获取ForEach方法的唯一类是List<>. 是否有丢失的原因(性能)?

采纳答案by Coincoin

There is already a foreach statement included in the language that does the job most of the time.

大多数情况下,语言中已经包含了一个 foreach 语句。

I'd hate to see the following:

我不想看到以下内容:

list.ForEach( item =>
{
    item.DoSomething();
} );

Instead of:

代替:

foreach(Item item in list)
{
     item.DoSomething();
}

The latter is clearer and easier to read in most situation, although maybe a bit longer to type.

后者在大多数情况下更清晰、更易于阅读,尽管键入时间可能会更长一些。

However, I must admit I changed my stance on that issue; a ForEach() extension method would indeed be useful in some situations.

但是,我必须承认我在这个问题上改变了立场;ForEach() 扩展方法在某些情况下确实很有用。

Here are the major differences between the statement and the method:

以下是语句和方法之间的主要区别:

  • Type checking: foreach is done at runtime, ForEach() is at compile time (Big Plus!)
  • The syntax to call a delegate is indeed much simpler: objects.ForEach(DoSomething);
  • ForEach() could be chained: although evilness/usefulness of such a feature is open to discussion.
  • 类型检查:foreach 在运行时完成,ForEach() 在编译时(Big Plus!)
  • 调用委托的语法确实简单得多:objects.ForEach(DoSomething);
  • ForEach() 可以被链接起来:尽管这样一个特性的邪恶/有用性是可以讨论的。

Those are all great points made by many people here and I can see why people are missing the function. I wouldn't mind Microsoft adding a standard ForEach method in the next framework iteration.

这些都是这里很多人提出的重要观点,我可以理解为什么人们缺少该功能。我不介意微软在下一个框架迭代中添加一个标准的 ForEach 方法。

回答by leppie

Most of the LINQ extension methods return results. ForEach does not fit into this pattern as it returns nothing.

大多数 LINQ 扩展方法都会返回结果。ForEach 不适合此模式,因为它不返回任何内容。

回答by aku

ForEach method was added before LINQ. If you add ForEach extension, it will never be called for List instances because of extension methods constraints. I think the reason it was not added is to not interference with existing one.

ForEach 方法是在 LINQ 之前添加的。如果添加 ForEach 扩展,由于扩展方法的限制,它永远不会被 List 实例调用。我认为没有添加它的原因是不干扰现有的。

However, if you really miss this little nice function, you can roll out your own version

但是,如果你真的错过了这个不错的小功能,你可以推出自己的版本

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

回答by Aaron Powell

I've always wondered that myself, that is why that I always carry this with me:

我一直想知道自己,这就是为什么我总是随身携带这个:

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);
    }
}

Nice little extension method.

不错的小扩展方法。

回答by TraumaPony

If you have F# (which will be in the next version of .NET), you can use

如果您有 F#(将在 .NET 的下一版本中),您可以使用

Seq.iter doSomething myIEnumerable

Seq.iter doSomething myIEnumerable

回答by user18784

Is it me or is the List<T>.Foreach pretty much been made obsolete by Linq. Originally there was

是我还是 List<T>.Foreach 几乎被 Linq 淘汰了。原来有

foreach(X x in Y) 

where Y simply had to be IEnumerable (Pre 2.0), and implement a GetEnumerator(). If you look at the MSIL generated you can see that it is exactly the same as

其中 Y 必须是 IEnumerable (Pre 2.0),并实现 GetEnumerator()。如果您查看生成的 MSIL,您会发现它与

IEnumerator<int> enumerator = list.GetEnumerator();
while (enumerator.MoveNext())
{
    int i = enumerator.Current;

    Console.WriteLine(i);
}

(See http://alski.net/post/0a-for-foreach-forFirst-forLast0a-0a-.aspxfor the MSIL)

(有关MSIL,请参阅http://alski.net/post/0a-for-foreach-forFirst-forLast0a-0a-.aspx

Then in DotNet2.0 Generics came along and the List. Foreach has always felt to me to be an implementation of the Vistor pattern, (see Design Patterns by Gamma, Helm, Johnson, Vlissides).

然后在 DotNet2.0 中泛型出现了列表。我一直觉得 Foreach 是 Vistor 模式的实现(参见 Gamma、Helm、Johnson、Vlissides 的设计模式)。

Now of course in 3.5 we can instead use a Lambda to the same effect, for an example try http://dotnet-developments.blogs.techtarget.com/2008/09/02/iterators-lambda-and-linq-oh-my/

现在当然在 3.5 中我们可以使用 Lambda 来达到相同的效果,例如尝试 http://dotnet-developments.blogs.techtarget.com/2008/09/02/iterators-lambda-and-linq-oh-我的/

回答by Scott Dorman

So there has been a lot of comments about the fact that a ForEach extension method isn't appropriate because it doesn't return a value like the LINQ extension methods. While this is a factual statement, it isn't entirely true.

因此,有很多关于 ForEach 扩展方法不合适的评论,因为它不像 LINQ 扩展方法那样返回值。虽然这是一个事实陈述,但并不完全正确。

The LINQ extension methods do all return a value so they can be chained together:

LINQ 扩展方法都返回一个值,以便它们可以链接在一起:

collection.Where(i => i.Name = "hello").Select(i => i.FullName);

However, just because LINQ is implemented using extension methods does not mean that extension methods mustbe used in the same way and return a value. Writing an extension method to expose common functionality that does not return a value is a perfectly valid use.

但是,仅仅因为 LINQ 是使用扩展方法实现的,并不意味着扩展方法必须以相同的方式使用并返回一个值。编写一个扩展方法来公开不返回值的通用功能是一种完全有效的用途。

The specific arguement about ForEach is that, based on the constraints on extension methods (namely that an extension method will neveroverride an inherited method with the same signature), there may be a situation where the custom extension method is available on all classes that impelement IEnumerable<T> except List<T>. This can cause confusion when the methods start to behave differently depending on whether or not the extension method or the inherit method is being called.

关于 ForEach 的具体争论是,基于对扩展方法的约束(即扩展方法永远不会覆盖具有相同签名的继承方法),可能存在自定义扩展方法在所有 imelement 类上可用的情况IEnumerable <T> 除了列表<T>。当方法开始表现不同时,这可能会导致混淆,具体取决于调用的是扩展方法还是继承方法。

回答by Paco

You can use select when you want to return something. If you don't, you can use ToList first, because you probably don't want to modify anything in the collection.

当你想返回一些东西时,你可以使用 select。如果不这样做,您可以先使用 ToList,因为您可能不想修改集合中的任何内容。

回答by Chris Zwiryk

While I agree that it's better to use the built-in foreachconstruct in most cases, I find the use of this variation on the ForEach<> extension to be a little nicer than having to manage the index in a regular foreachmyself:

虽然我同意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;
}
例子
var people = new[] { "Moe", "Curly", "Larry" };
people.ForEach((i, p) => Console.WriteLine("Person #{0} is {1}", i, p));

Would give you:

会给你:

Person #0 is Moe
Person #1 is Curly
Person #2 is Larry

回答by mancaus

The discussion heregives the answer:

这里的讨论给出了答案:

Actually, the specific discussion I witnessed did in fact hinge over functional purity. In an expression, there are frequently assumptions made about not having side-effects. Having ForEach is specifically inviting side-effects rather than just putting up with them. -- Keith Farmer (Partner)

实际上,我目睹的具体讨论实际上取决于功能纯度。在表达式中,经常有关于没有副作用的假设。拥有 ForEach 是特别引人注意的副作用,而不仅仅是忍受它们。——基思·法默(合伙人)

Basically the decision was made to keep the extension methods functionally "pure". A ForEach would encourage side-effects when using the Enumerable extension methods, which was not the intent.

基本上决定保持扩展方法在功能上“纯”。ForEach 会在使用 Enumerable 扩展方法时鼓励副作用,这不是本意。