2

いくつかのメソッドを呼び出すと、コレクションのそのインスタンスにリンクされているLINQクエリ全体の実行が開始されることを知っています。

たとえば、私が呼び出すたびに.Count()。そして、私が呼び出すたびにも思います.ToList()

ToList()を取得した後、そのコレクションの「コピー」を実行します。コレクションの新しいインスタンスにLINQクエリを記述しない場合、Count()は何も実行しません。(右?)

.Union()そして、私が2つのリストに電話した場合はどうなりますか?と2Ienumerable?そして.Except()それは同じですか?

トレース/診断を試してみましたが、LINQクエリがいつ実行されるかがよくわかりません。

4

3 に答える 3

2

Union と Except は遅延実行されます。詳細については、ドキュメントの備考セクションを参照してください。

http://msdn.microsoft.com/en-us/library/bb341731

http://msdn.microsoft.com/en-us/library/bb300779

また、そのような状況では、内部で何が起こっているのかがはっきりしている場合は、Reflector またはその他の .NET 逆コンパイラを使用できます。本当に助かります。

于 2012-07-20T10:43:14.367 に答える
1

あなたの質問に対する答えは、次の 2 つのオプションによって異なります。

  • 操作のタイプ: 遅延 (または遅延) および貪欲。遅延操作はすぐには実行されず、コードが linq ソースからデータの具体化を開始するまで延期されます。貪欲な操作は常にすぐに実行されます。
    • 遅延操作の例: .Union.Except.Where、 。Selectおよび他のほとんどの linq 操作
    • 貪欲なのは: .ToList.Count .ToArrayおよびデータを具体化するすべての操作
  • linq 操作のデータ ソース。Linq to Memory を使用している間、すべての操作 (レイジーと貪欲の両方) がすぐに実行されます。通常、データの外部ソースへのLinqは、実体化中にのみ遅延操作を実行します。

この 2 つのルールを使用すると、linq がどのように動作するかを予測できます。

  1. .Count.ToListすぐに実行され、データが具体化されます
  2. の後.ToList、メモリでコレクションを取得し、後続のすべての操作がすぐに実行されます (.Countもう一度実行されます) 。
  3. 怠惰または貪欲としてどのよう.Unionに動作するかは、データ ソースのタイプによって異なります。.Exceptメモリの場合は貪欲になり、SQL は遅延します。

LinqPadの例。貪欲なorを使用してマテリアライズする前後に、1つとEnumerable遅延または延期さ.Whereれた操作があります。.Select.Count.ToList

void Main() 
{ 
    "get enumerable".Dump(); 
    var samplesEnumerable = GetSamples(); 

    "get count on enumerable #1".Dump(); 
    samplesEnumerable.Count().Dump(); 

    "get enumerable to list #1".Dump();  
    var list = samplesEnumerable.ToList();   

    "get count on list #1".Dump();   
    list.Count().Dump(); 

    "get count on list again #2".Dump(); 
    list.Count().Dump(); 

    "get where/select enumerable #1".Dump(); 
    samplesEnumerable 
        .Where(sample => { sample.Dump(); return sample.Contains("5"); }) 
        .Select(sample => { sample.Dump(); return sample; })
        .Dump(); 

    "get where/select list #1".Dump(); 
    list 
        .Where(sample => { sample.Dump(); return sample.Contains("5"); }) 
        .Select(sample => { sample.Dump(); return sample; })
        .Dump(); 
} 

string[] samples = new [] { "data1", "data2", "data3", "data4", "data5" }; 

IEnumerable<string> GetSamples() 
{ 
    foreach(var sample in samples)  
    { 
        sample.Dump(); 
        yield return sample; 
    } 
}

サンプル出力。キーポイント

  1. マテリアライズされていないデータでは、すべて.Count.Listデータが何度も何度もデータを取得しています

    • get count on enumerable #1
    • get where/select enumerable #1
  2. データを実体化した後、列挙型は取得されなくなります

    • get enumerable to list #1
    • get count on list #1
    • get count on list again #2
    • get where/select list #1

出力:

get enumerable
get count on enumerable #1
data1
data2
data3
data4
data5

5
get enumerable to list #1
data1
data2
data3
data4
data5
get count on list #1

5
get count on list again #2

5
get where/select enumerable #1
data1
data1
data2
data2
data3
data3
data4
data4
data5
data5
data5

data5 

get where/select list #1
data1
data2
data3
data4
data5
data5

data5
于 2012-07-20T11:01:40.203 に答える
0

Linq クエリは、基になるコレクションがあるがコレクションでない場合に実行されます。たとえば、ToList()またはを使用してクエリを具体化できますToArray

すべての遅延実行拡張機能は、最初にを an (インデクサーが必要な場合はfe ) または a (必要な場合は fe )Enumerableにキャストしようとします。可能であれば、クエリを実行する必要のない「ネイティブ」メソッドを使用します。それ以外の場合は、シーケンスを列挙します。IEnumerable<T>IList<T>ICollection<T>Count

MSDNで用語 deferredを検索して、メソッドが executexd deferred であるか、またはすぐに実行されるかを確認しますソース コード (fe via ) を調べると、.ILSpyyield keyword

UnionExcept遅延実行を使用して実装されます。したがって、 その結果を保持したい場合はToList/が必要です。ToArray

の実装の例を次に示しますEnumerable.Count

ICollection<TSource> collection = source as ICollection<TSource>;
if (collection != null)
{
    return collection.Count;
}
ICollection collection2 = source as ICollection;
if (collection2 != null)
{
    return collection2.Count;
}
int num = 0;
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
    while (enumerator.MoveNext())
    {
        num++;
    }
}
return num;
于 2012-07-20T10:44:32.507 に答える