Where()的意外结果

时间:2017-02-21 15:32:55

标签: c# linq

我有这个代码,它应该返回一个值类型,在每一步应用steps中指定的转换。

private static T Transformed<T>(T x, params Func<T, T>[] steps) where T : struct
{
     if ((steps?.Length ?? 0) == 0)
     {
        return x;
     }

     var reallyEmpty = steps.Where(f => (x = f(x)).Equals(int.MinValue));
     return x;
}

我只需要Where扩展即可在不使用循环的情况下完成每个步骤,因此我使用的条件可能永远不会为真(Equals(int.MinValue))。 但如果我有这个调用代码,我会得到5而不是15,这是我期望的。

int res1 = Transformed(5, x => x * 2, x => x + 5);
Console.WriteLine(res1);

我的问题是为什么? Where不会检查每个元素并检查它吗?

2 个答案:

答案 0 :(得分:12)

Where被懒惰地评估 - 你永远不会使用它的结果,所以谓词永远不会被评估。

可以通过计算结果或类似的方式来强制迭代:

var ignored  steps.Where(f => (x = f(x)).Equals(int.MinValue)).Count();

......但是让自己循环会更清楚:

foreach (var step in steps) 
{
    x = step(x);
}

毕竟,你不是真的通过使用Where来避免循环 - 你只是隐藏它,并且这样做会使你的代码过于复杂到你不明白了。

答案 1 :(得分:2)

如果您真的开始使用LINQ,可以使用Aggregate执行您想要的操作:

private static T Transformed<T>( T x, params Func<T, T>[] steps ) where T : struct
{
    return steps?.Aggregate( x, ( accum, f ) => f( accum ) ) ?? x;
}

我通常不会发现聚合特别易读,但我认为值得一提。