【问题标题】:why ForEach Linq Extension on List rather than on IEnumerable [duplicate]为什么 ForEach Linq 扩展在 List 而不是 IEnumerable [重复]
【发布时间】:2011-08-07 23:29:10
【问题描述】:

可能重复:
Why is there not a ForEach extension method on the IEnumerable interface?

你好,

我的问题是为什么 Foreach 扩展方法是在 List 而不是 IEnumreable 上定义的。我已经阅读了 Eric Lippert 的 article,但关键是,如果拥有这样的方法是如此糟糕,那么为什么要使用 List 呢?

【问题讨论】:

  • 你在说哪个 ForEach? List<> 没有。
  • 确实如此。 msdn.microsoft.com/en-us/library/bwabdf9z.aspx 我个人不同意那篇文章的基本原理,即它不会提高可读性。这是主要的好处,完全出于这个原因它是一个有用的好处。为IEnumerable<T> 创建可链接的扩展方法很简单。
  • 也许您可以阅读 Eric 对他文章的第一条评论的回答,以回答您的问题。
  • 我喜欢他的回答:一只手不知道另一只手在做什么,基本上。
  • 他们忙于思考是否可以,他们从未停止思考是否应该在桌子上猛击拳头(谢谢你,侏罗纪公园)

标签: c# .net linq ienumerable linq-to-objects


【解决方案1】:

List<T>.ForEach() 不是扩展方法。这只是List<T>上的一个方法。

它在 LINQ(即Enumerable)中不可用的主要原因之一是 LINQ 查询应该没有副作用(例如,您可以多次执行查询并获得相同的结果而不改变它们),这使得它们非常可组合。所有接受委托的LINQ操作都是针对Func;他们都不接受Action 代表。

【讨论】:

  • 你能发布一个副作用的例子,它会改变 foreach 中列表的内容,在 IEnumerable 的情况下不能或不可能?在我看来,ForEach 只是列表中 IEnumerable 的枚举。
  • 一个例子是list.ForEach(x=>list.Remove(x)) .List<T>.ForEach()不使用IEnumerable<T>接口——该方法直接索引一个数组。如果在使用枚举器迭代集合时修改了集合,则会引发异常。
  • 嗯,这是一个错误,实现了一半的功能,MSDN 没有任何地方显示 ForEach 是专门添加来枚举修改后的集合的。看我的回答。
【解决方案2】:

这是我在 Microsoft Connect 网站上发布的一个错误,Microsoft 已经在即将发布的 .NET 版本中修复了它,如下链接中所述。

List.ForEach allows enumeration over modified version of List

这可能与答案没有直接关系,但我刚刚发现的内容很有趣。

ForEach,删除(有效)

List<int> list = new List<int>(){ 1, 2, 3, 4, 5, 6};

list.ForEach(x => {
    Console.WriteLine(x);
    list.Remove(x);
});

foreach,删除(崩溃)

// throws exception
foreach (var x in list)
{
    Console.WriteLine(x);
    list.Remove(x);
}

ForEach,插入 (...)

// goes in infinite loop...
list.ForEach(x => {
    list.Add(1);
});

foreach,插入(崩溃)

// throws exception
foreach (var x in list)
{
    Console.WriteLine(x);
    list.Add(x);
}

所以任何在这里谈论可变性或不同的混淆层等的人,我认为这完全是 Visual Team 实现的一半功能,因为如果修改集合,枚举总是会导致问题。

尽管有争论,我仍然认为 ForEach 没有理由允许修改,它纯粹用于枚举,无论是 foreach(var item in x) 语法还是 x.ForEach(x=>{} ) 语法。

我不同意 Eric,我只是看到 BCL 团队在 IEnumerable 和 list.ForEach 上实现了这个功能是有问题的。

“为什么”是完全主观的,例如,Silverlight 添加了复杂的散列算法并将 MD5 抛在后面,而我们在其他任何地方都如此广泛地使用 MD5。它更多的是需要多少东西,以及谁选择是否将其包含在框架中。

在 IEnumerable 中没有 ForEach 根本没有任何逻辑或哲学原因。有很多这样的缺失点,我认为 .NET 会随着时间的推移而改进。

【讨论】:

  • +1 很好地说明了应该如何使用枚举
  • 您在谈论添加或删除列表的修改,这(明智地)foreach 不允许。我认为 List 实现也不应该——所以它必须从上到下按索引访问以进行迭代。但是有很多原因可能会导致您想要遍历列表并导致对列表本身没有破坏性的副作用,例如更改成员的属性,或使用列表中的信息做一些不相关的事情。
  • 更改项目的属性与列表的可变性无关,请列出一个副作用,它应该同时影响列表和枚举,这是 IEnumerable 无法实现的
【解决方案3】:

归根结底是应该避免并且不鼓励使用 LINQ 来改变状态,LINQ 的重点是查询和转换数据,而不是就地突变 - 你失去了 LINQ 函数式方法的许多好处(即没有副作用,相同的输入产生相同的输出)如果你改变状态。

Linq 提供 ForEach() 扩展方法而不是普通的 foreach 循环没有任何好处,除了它会帮助你进入变异状态 - 因此它没有实现(至少这是我的看法,带着它一粒盐)。

【讨论】:

    【解决方案4】:

    “为什么”超出了我的范围;我没有制作 C#。但是,这是有道理的,因为它将完全枚举您的集合,而大多数 LINQ 运算符都是惰性求值的。

    【讨论】:

    • 嗯? Count()也可以这样说
    • 或任何选择器。陈述的理由是 Linq 应该从列表中返回内容,而不是对列表进行操作。这作为一个前提很好,但我想不出首先从这个前提开始的充分理由。
    • 为了更容易实现 IQueryable?
    猜你喜欢
    • 2011-04-13
    • 1970-01-01
    • 1970-01-01
    • 2013-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-23
    • 1970-01-01
    相关资源
    最近更新 更多