2

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()、まったく呼び出されますか?
  • stuffrecordName「foobar」と等しい場合にのみ必要です。DoSomethingIntensiveWith()すべてのレコードに対して実行されますか、または「foobar」に等しいレコードのみに対して実行されます recordNameか?

「foobar」に等しいDoSomethingIntensiveWith()場合にのみ呼び出される ようにしたい場合は、次のように、節の後にカルセ を配置する必要がありますか?recordNameletwhere

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

それまでの間、実際のコードとデバッガーで遊んでみます。見つけたものはまた報告します。

4

1 に答える 1

2

これが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();    
    }
}

次に、最初のクエリはプロジェクトをフィルタリングし(したがって、一致するレコードに対してのみコストのかかる操作を実行します)、2番目のクエリは両方のコストのかかる操作を計算します。

query1:
abc
query2:
abc
def

letこれは、実際には次の方法で実装されていることに注意してください。これSelectは、ソースデータからクエリの内部で使用される匿名型への射影です。

于 2012-11-05T11:59:28.523 に答える