在C# LINQ中,可以为Union启用谓词合并和下推吗?

问题描述 投票:0回答:1

这是一个演示该问题的简短示例:

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));

为什么还没有完成?如果可以的话如何启用?

c# linq functional-programming query-optimization predicate
1个回答
0
投票

我认为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))

生成完全不同的结果
© www.soinside.com 2019 - 2024. All rights reserved.