【问题标题】:Is there a way to set values in LINQ?有没有办法在 LINQ 中设置值?
【发布时间】:2011-12-11 21:55:44
【问题描述】:

有没有更好的方法来使用 LINQ 完成这些任务?

IEnumerable<SideBarUnit> sulist1 = newlist.Where(c => c.StatusID == EmergencyCV.ID);
foreach (SideBarUnit su in sulist1) su.color = "Red";

【问题讨论】:

标签: c# linq


【解决方案1】:

最简单的方法是定义一个foreach 扩展方法,允许您将其添加到此类查询的末尾。例如

public static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action) {
  foreach (var cur in enumerable) {
    action(cur);
  }
}

...

用法:

newlist
  .Where(c => c.StatusID == EmergencyCV.ID)
  .ForEach(cur => cur.color = "Red");

【讨论】:

    【解决方案2】:

    没有。

    您可以这样做,正如此处的其他答案所指出的那样,但是您不再使用 LINQ

    Eric Lippert 写了an excellent blog post about this very subject,我强烈建议您阅读。摘录如下:

    在哲学上反对提供这种方法,原因有两个。

    第一个原因是这样做违反了所有其他序列运算符所基于的函数式编程原则。显然调用此方法的唯一目的是产生副作用。

    表达式的目的是计算一个值,而不是产生副作用。

    ...

    第二个原因是这样做会给语言增加零新的表示能力。这样做可以让你重写这段非常清晰的代码:

    foreach(Foo foo in foos){ statement involving foo; }
    

    进入这段代码:

    foos.ForEach((Foo foo)=>{ statement involving foo; });
    

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

    【讨论】:

    • +1 其他人已经提到它,其他人已经继续并展示了 ForEach() 的示例。我完全同意 Eric Lippert 的观点。也许明确发布此摘录会说服 OP,也可能不会。不过,最好的答案是 IMO。
    【解决方案3】:

    使用List.ForEach()方法:

    IEnumerable<SideBarUnit> sulist1 = 
       newlist.Where(c => c.StatusID == EmergencyCV.ID)
              .ToList()
              .ForEach(item => item.color = "Red");
    

    PS:我知道 Eric Lippert 的 article 关于 ForEach() vs foreach,但无论如何它很有用,我更喜欢它而不是 for/foreach 循环

    编辑:关于评论中关于性能命中的问题

    Enumerable.ToList() 实现为

    public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
    {
        if (source == null)
        {
            throw Error.ArgumentNull("source");
        }
        return new List<TSource>(source);
    }
    

    所以性能下降是时候创建一个新的List&lt;&gt;() 实例了。

    MSDN 为List<>(IEnumerable<>)ctor 说下一个:

    初始化包含元素的 List 类的新实例 从指定集合复制,并且有足够的容量容纳复制的元素数量。

    所以会有所有列表的复制操作

    【讨论】:

    • 也就是说集合循环了两次
    • ForEach 不是 Linq 独有的“功能”。事实上,它与 Linq 完全无关。所以,我假设你的答案,真的,是“不,但这里有一个替代方案。”关于 why 的建议将是这个答案的一个很好的输入 - 而不是 OP 带着这是 Linq 的错误印象。
    • @Mr.失望:绝对,LINQ 在ToLisT() 调用之后结束
    【解决方案4】:

    Linq 是关于选择,而不是更新。 但是你可以使用 ToList 和 List 的 ForEach 来更新元素:

    newlist.Where(c => c.StatusID == EmergencyCV.ID).
      ToList().
      ForEach(su => su.color = "Red");
    

    我不确定可读性是否更好......

    【讨论】:

    • @vs 74 从 IEnum 转换为 List 时是否会影响性能?
    • @iterationx,好吧,将创建一个新列表,因此它不如迭代高效 + 我认为它的可读性较低,所以我不确定是否值得使用这种技术......
    【解决方案5】:

    您可以在 Select 语句中使用匿名方法:

    var sulist1 = newlist.Where(c => c.StatusID == EmergencyCV.ID)
                         .Select(c => {
                                         c.color = "Red";
                                         return c;
                                      });
    

    【讨论】:

    • 实际上,除非迭代新列表,否则我认为这不会起作用
    【解决方案6】:

    LINQ 的目的主要是查询/投影/转换数据。

    您可能想要使用 ForEach 扩展方法。但请参阅this discussion 了解更多详情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-21
      • 1970-01-01
      • 2012-03-09
      • 2011-07-11
      相关资源
      最近更新 更多