我对 LINQ 表达式的编译和优化以及是否需要仔细考虑表达式中 let 和 where 子句的顺序感兴趣。
这里是示例:
var query =
from record in Database.Table
let recordName = record.GetName()
let notUsed = UselessData()
let stuff = DoSomethingIntensiveWith(record)
where recordName == "foobar"
select stuff;
foreach (string item in query) {
Console.WriteLine("item => '{0}'", item);
}
问题/假设:
record.GetName()
必须解析才能执行where
条款。notUsed
从未在表达式中使用,因此将调用UselessData()
完全吗?
仅当 stuff
。将要DoSomethingIntentialWith()
对每条记录或仅记录执行 其中recordName
等于“foobar”?
recordName
等于“foobar”时才需要 如果我想确保仅在以下情况下调用 DoSomethingIntentialWith()
recordName
等于“foobar”,我是否需要将 let
caluse 放置在
where
子句,如下:
var query =
from record in Database.Table
let recordName = record.GetName()
let notUsed = UselessData()
where recordName == "foobar"
let stuff = DoSomethingIntensiveWith(record)
select stuff;
foreach (string item in query) {
Console.WriteLine("item => '{0}'", item);
}
与此同时,我将使用一些真实的代码和调试器。患病的 报告我的发现。
最佳答案
如果这是 LINQ-to-Objects,那么:是的,您知道。标准 Enumerable.*
实现在按顺序应用事物方面非常直接。您不一定需要所有 let
子句,但事情仍然按顺序完成,并且该顺序受到尊重。如果它是 LINQ-to-anything-else,那么一切都失败了。
这很容易演示:
using System;
using System.Linq;
class Foo
{
public Foo(string value)
{
Value = value;
}
public string Value { get; private set; }
public string Expensive()
{
Console.WriteLine(Value);
return Value;
}
static void Main()
{
var foos = new[] {
new Foo("abc"),
new Foo("def")};
Console.WriteLine("query1:");
var query1 = (from obj in foos
let val = obj.Value
where val.StartsWith("a")
let result = obj.Expensive()
select result).ToArray();
Console.WriteLine("query2:");
var query2 = (from obj in foos
let val = obj.Value
let result = obj.Expensive()
where val.StartsWith("a")
select result).ToArray();
}
}
第一个查询过滤然后项目(因此它只对匹配记录执行昂贵的操作),而第二个查询计算两者的昂贵操作:
query1:
abc
query2:
abc
def
应该注意的是,let
实际上只是通过Select
实现的 - 它是从源数据到查询内部使用的匿名类型的投影。
关于c# - LINQ查询优化: specifically, let子句的位置重要吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13231500/