2013-08-03 22 views
4
//var sample= new { bottom=2, top=5,count=4}; 
var sample= new [] {2,3,4,5,6}; 
var q = from x in new int[]{0} //force desired behavior 
    from i in sample 
    from j in sample 
    select Math.Pow(i,j); 


q.Distinct().Count().Dump(); 
sample = new[]{2,3,4,5}; 
//q = from i in Enumerable.Range(sample.bottom, sample.top-sample.bottom+1) 
// from j in Enumerable.Range(sample.bottom, sample.top-sample.bottom+1) 
// select checked(System.Numerics.BigInteger.Pow((BigInteger)i,j)); 
q.Distinct().Count().Dump(); 

第二個答案是不正確每次如果from x line不存在,或者q變量的復位未完成。(這裏顯示註釋掉)什麼決定了變量是否關閉?

最初的樣本是一個匿名的變量,但數組做它也是。

var sample = new { bottom =2, top=5};

這是否與此Scope of Linq Expressions defined in a loop - At issue: closing over loop variable

爲什麼在頂部放置一個物品數組修復了封口?

+2

你的問題與懶惰評估不關閉。 – Hogan

+0

難道不是兩個?從某種意義上說,這是懶惰的評價,其中一部分是熱切評價的,另一部分是懶洋洋地評價的。這對我來說是一個閉幕,一個不是。 – Maslow

+0

這似乎同意我們倆。 http://stackoverflow.com/questions/428617/what-are-closures-in-net – Maslow

回答

2

第一步,瞭解什麼是怎麼回事是瞭解一個查詢表達式是如何轉化。根據規範要求:

from x1 in e1 
from x2 in e2 
select v 

被翻譯成

e1.SelectMany(x1 => e2, (x1, x2) => v) 

這是令人難以置信的重要理解。 from x1 in e1 from x2 in e2 select v的結果是對e1的查詢,不管e1是什麼;它是固定的,期間。

現在,這是問題所在。讓我們看看你的查詢。

var q = from i in sample 
     from j in sample 
     select Math.Pow(i, j) 

sample在在查詢被構造時的值是將數組創建表達new[] { 2, 3, 4, 5, 6 }的結果的參照。令e1是對該數組創建表達式的結果的引用。然後查詢變爲:

e1.SelectMany(i => sample, (i, j) => Math.Pow(i, j)); 

固定,期間,無論你重新分配給sample什麼。也就是說,你

var sample = new[] { 2, 3, 4, 5, 6 } 
var q = from i in sample 
     from j in sample 
     select Math.Pow(i, j) 

var sample = new[] { 2, 3, 4, 5, 6 }; 
var e1 = sample; 
var q = e1.SelectMany(i => sample, (i, j) => Math.Pow(i, j)); 

現在,sample關閉了,這就是爲什麼後您分配一個新值sample,你看一個不同的查詢結果。但是無論如何e1保持固定爲陣列創建表達式new[] { 2, 3, 4, 5, 6 }的結果。

但是,當你開始查詢

var q = from x in new int[] { 0 } 
     from i in sample 
     from j in sample 
     select Math.Pow(i, j) 

現在查詢轉換爲

int[] e1 = new int[] { 0 }; 
var q = e1.SelectMany(
    x1 => sample.SelectMany(i => sample, (i, j) => Math.Pow(i, j) 
); 

現在sample被捕獲作爲兩個i序列j,但e1已修復。

+0

+1你在OP的問題中的第一個查詢的翻譯可能比我的更準確。 –

+0

有沒有寫這樣的方法,整個查詢被正確關閉而沒有引入虛假的1項目數組,但它仍然按需要工作? – Maslow

2

此代碼兩次關閉sample

from x in new int[]{0} 
from i in sample 
from j in sample 
select Math.Pow(i,j); 

的實際方法調用此計算結果爲是:

new int[] {0} 
    .SelectMany(x => sample, (x, i) => new {x, i}) 
    .SelectMany(@t => sample, (@t, j) => Math.Pow(@t.i, j)); 

此代碼關閉了sample一次。

from i in sample 
from j in sample 
select Math.Pow(i,j); 

的實際方法調用此計算結果爲是:

sample.SelectMany(i => sample, (i, j) => Math.Pow(i, j)); 

所以,如果你改變sample,只有i => sample拉姆達會「看到」的sample「新」值; sample.SelectMany已經以「舊」值運行。

這兩個例子都會導致R#發出訪問修改後的封鎖警告,這通常是一個大紅旗。考慮保持的sample私有副本爲您的每個查詢,或有一個函數的參數爲​​你做它:

IEnumerable<int> SelectManyPow(int[] sample) 
{ 
    return from i in sample 
      from j in sample 
      select Math.Pow(i, j); 
} 
相關問題