【问题标题】:Is it possible to convert foreach operation into LINQ if it does two things?如果它做两件事,是否可以将 foreach 操作转换为 LINQ?
【发布时间】:2016-01-18 16:10:15
【问题描述】:

我的 工作 foreach 如下。

List<Thing> things = new List<Thing>();
foreach (Original original in originals)
  things.Add(new Thing(orignal));

然后,我变聪明了,将其 LINQ 化为以下仍在工作代码。

IEnumerable<Thing> things = originals.Select(origo => new Thing(origo));

为减少行数感到非常自豪,并且我自己 LINQing 到更清晰的代码我意识到还需要更新进程表。当我们进行转换时,更新必须同时发生。所以,夹在两腿之间,感觉不那么自豪了,我回到原来的代码,添加了通知方法。

List<Thing> things = new List<Thing>();
foreach (Original original in originals)
{
  things.Add(new Thing(orignal));
  DoTell();
}

我的问题是,是否可以保留 LINQie 语法并且仍然能够以某种方式合并柜员。我不希望代码看起来不错,也不会以这种方式更具可读性(尽管如果是这样的话,那就太棒了)。然而,现在这是一个学术好奇心和纯粹固执的问题 - 我想知道它是否可以完成

【问题讨论】:

标签: c# linq foreach


【解决方案1】:
originals.ToList().ForEach(x=>{things.Add(new Thing(x));DoTell();});

【讨论】:

  • List.ForEach 不是来自 Linq
  • 这看起来不错。但它仍然一个接一个地添加元素。我在做这做那方面考虑得更少。相反,我正在寻找选择这个和做那个。尽管如此,仍然是一个不错的语法,所以 +1。
  • 事实上 List.ForEach 不是建议调用,请查看 Eric Lippert 的链接
  • @MrinalKamboj 我看不到你指的是哪个链接。
  • @KonradViltersten 评论了这个问题,重新粘贴了链接 Eric Lippert:blogs.msdn.com/b/ericlippert/archive/2009/05/18/…
【解决方案2】:
originals.ForEach(q =>
{
   //do first thing
   //do second thing 
});

【讨论】:

  • 正如我在另一篇文章中评论的那样 - 我更喜欢 select-do 而不是 do-do。这可能吗?
【解决方案3】:

有一种非常丑陋的方法可以做到这一点。它纯属学术性

IEnumerable<Thing> things = originals.Select(origo => {DoTell(); return new Thing(origo)});

您将更新您的表格并在Select 中返回new Thing。选择不会失败,因为您在其中使用括号并告诉您只返回 new Thing 而不是 DoTell() 的结果

我建议你使用foreach,因为它最终会看起来更干净。在任何地方使用 LINQ 都不是更清洁/更清晰代码的解决方案。

编辑:

如果你仍然想使用 LINQ,你可以做更丑的版本(单线):

var things = things.Select(x => new { o = new Thing(), b = DoTell()}).Select(x=>x.o);

这种方法纯属邪恶。但是它可以在没有返回语句的情况下工作:)

【讨论】:

  • 我同意。 LINQ 确实美化了代码,但仅在必要时才进行
  • 哦,那里有一个很好的代码均衡。现在,您确实回答了这个问题。但是,如果我们引入额外的要求,即不得在创建 Thing 之前执行告知,该怎么办?我们当然可以存储东西,做告诉然后返回。但我想知道是否有办法在没有 return 语句的情况下处理它。 (无论如何,对于创造力来说都是巨大的 +1。)
  • @KonradViltersten 正如我所说,purely academic :) 我认为这里的 linq 不是一个选项。 Language INtegrated Query 表示它用于查询而不是循环或修改数据。然而,如果需要一些扩展来编写类似 LINQ 的代码来保存/修改数据,那么这个问题就会引发讨论。
  • @KonradViltersten 没有回报就做到了 linq 风格。
  • @wudzik 这个答案是最好的,+1
【解决方案4】:

这应该工作,使用原始选择语法

IEnumerable<Thing> things = originals.Select(origo => 
                                                    {
                                                       DoTell();
                                                       return new Thing(origo);
                                                     });

如果DoTell() 需要作为后调用,并且需要使用为某些内部用途而创建的new Thing,这在此代码中不明显,则执行以下操作:

IEnumerable<Thing> things = originals.Select(origo => 
                                                        {
                                                           var thing = new Thing(origo);
                                                           DoTell();
                                                           return thing;
                                                         });

【讨论】:

  • 用户 @wudzik 打败了你,但仍然 +1 回复。请查看我对他的回答的评论。有什么方法可以避免 return 并且仍然达到结果? (至此,问题已经得到解答。我只是特别好奇。)
  • 谢谢,我知道我回复有点慢,但是在同一个 Select 调用中没有返回,机会更少,不过让我检查一下替代方法
  • @KonradViltersten 只是大声思考,如果您可以从被调用的 Thing 类构造函数中调用 DoTell,那么原始简洁代码本身就可以工作,但这可能不是一个很好的编程实践。否则您可能需要考虑扩展方法
【解决方案5】:

附加说明 ForEach 返回类型为 void 但 Select 具有返回类型 IEnumerable。 所以两者的使用取决于上下文。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-19
    • 1970-01-01
    • 2019-12-12
    • 2020-07-21
    • 1970-01-01
    • 2021-06-05
    • 2021-07-07
    • 1970-01-01
    相关资源
    最近更新 更多