C# 和 LINQ - 任意语句而不是 let

C# and LINQ - arbitrary statement instead of let

假设我正在执行这样的 LINQ 查询(顺便说一句,这是 LINQ to Objects):

var rows = 
    from t in totals
    let name = Utilities.GetName(t)
    orderby name
    select t;

因此 GetName 方法只是从 Total 对象计算显示名称,并且是对 let 关键字的恰当使用。但是假设我有另一种方法 Utilities.Sum(),它对 Total 对象应用一些数学运算并在其上设置一些属性。我可以使用 let 来实现这个,就像这样:

var rows =
    from t in totals
    let unused = Utilities.Sum(t)
    select t;

这里很奇怪的是 Utilities.Sum() 必须 return 一个值,即使我不使用它。如果 returns void,有没有办法在 LINQ 语句中使用它?我显然不能做这样的事情:

var rows =
    from t in totals
    Utilities.Sum(t)
    select t;

PS - 我知道在 LINQ 表达式中调用具有副作用的方法可能不是好的做法。只是想完全理解 LINQ 语法。

不,没有对 IEnumerable<T> 中的所有项目执行 Action 的 LINQ 方法。它是 very specifically left out,因为设计师积极地不希望它在那里。

回答问题

不,但是你可以通过创建一个 Func 来作弊,它只调用预期的方法并吐出一个随机的 return 值,例如 bool

Func<Total, bool> dummy = (total) => 
    { 
        Utilities.Sum(total);
        return true;
    };

var rows = from t in totals
           let unused = dummy(t)
           select t;

但这不是一个好主意 - 它不是特别可读。


幕后的让statement

上面的查询将转换为类似于此的内容:

var rows = totals.Select(t => new { t, unused = dummy(t) })
                 .Select(x => x.t);

所以如果你想使用方法语法而不是查询语法,另一个选择是:

var rows = totals.Select(t =>
               {
                   Utilities.Sum(t);
                   return t;
               });

稍微好一点,但仍然在滥用 LINQ。


...但是你应该做什么

但我真的看不出有什么理由不简单地分别循环计算总数:

foreach (var t in totals)
    Utilities.Sum(t);

您应该从 Microsoft 的 Reactive Extensions 团队下载 "Interactive Extensions" (NuGet Ix-Main)。它有很多有用的扩展。它会让你这样做:

var rows =
    from t in totals.Do(x => Utilities.Sum(x))
    select t;

它允许对遍历的可枚举产生副作用。

请阅读我对问题的评论。实现此类功能的最简单方法是使用如下查询:

var rows = from t in totals
    group t by t.name into grp
    select new 
    {
        Name = t.Key,
        Sum = grp.Sum()
    };

以上查询returns IEnumerable object.

更多信息,请参阅:101 LINQ Samples