这是一个演示该问题的简短示例:
var numbers = Enumerable.Range(1, 10);
var n2 = numbers.Select(
v =>
{
Debug.Log(v);
// some long operation
return v;
}
);
var query1 = n2.Where(n => n == 2);
var query2 = n2.Where(n => n == 3);
var unionResult = query1.Union(query2).ToList();
foreach (var i in unionResult) Console.WriteLine(i);
执行时,日志将指示
numbers
的每个元素被访问两次,这是有问题的,不仅因为在这种情况下访问元素可能是一个昂贵的操作,而且 numbers
可能是一个流,它的每个元素仅可用一次。
我认为LINQ的底层机制可以轻松地合并2个谓词以产生最佳执行,这相当于:
var unionResult = n2.Where(n => (n == 2 || n == 3));
为什么还没有完成?如果可以的话如何启用?
我认为LINQ的底层机制可以轻松地合并2个谓词以产生最佳执行,这相当于:
不,实际上不能,因为在一般情况下无法证明传递的函数是纯函数(例如,您已经对
Debug.Log
产生了副作用)。例如,想象一下以下内容:
var numbers = Enumerable.Range(1, 10);
var n2 = numbers.Select(v =>
{
var res = Random.Shared.Next(v); // here can be any function, for example mutating shared state
Debug.Log(res);
return res;
});
这应该为
var unionResult = query1.Union(query2).ToList();
和 n2.Where(n => (n == 2 || n == 3))
生成完全不同的结果