2016-02-09 34 views
0

這是我的理解,下面的代碼是安全的,因爲Invoke是同步的,所以索引總是在動作後增加,但我得到了array.ElementAt(index)行的ArgumentOutOfRangeException報告。在下面的代碼中,修改閉包是否有可能存在錯誤?

數組是一個IEnumerable,它是在此代碼之前由LINQ查詢生成的,因此無法修改。

IEnumerable array = collection.Select(() => .....); 

while (index < array.Count()) 
{ 
    this.CurrentDispatcher.Invoke(new Action(() => 
    { 
     ... 
     object a = array.ElementAt(index) 
     ... 
    }), DispatcherPriority.Input); 

    index++; 
} 

我能想象得到ArgumentOutOfRangeException的唯一方法是,如果,不知何故,被訪問前陣指數得到提高。

這有可能以任何方式嗎?

+1

什麼是「收藏」?你是否意識到你正在評估'Count'每次調用的'Select'部分以及每次調用'ElementAt'?這裏的名稱「數組」很容易讓人誤解...... –

+1

你的'Enumerable.Select'方法裏面有什麼?每當你調用'ElementAt'和'Count'時,基礎查詢可能會產生不同的結果,因爲你沒有實現查詢 –

+0

好吧,我明白你的意思了。我怎樣才能實現查詢?你能把它當作答案嗎? –

回答

3

由於array是懶惰的,即使您使用緩存的本地變量更正了代碼,集合中的更改也會導致索引超出範圍(即從collection中刪除元素)。

或者如在Select中所指出的註釋條件,每次執行時可能會返回不同的結果。

請注意,如果您有R#,您將獲得「可能的多個枚舉」警告,因爲array.Count()array.ElementAt()都需要遍歷集合以實現結果。所以你真的在while循環中多次重複執行Select

修正:

  • 執行迭代之前與foreach(優選)
  • 力的可枚舉與ToList()通話評價執行單次迭代(其也將降低爲O(n^2)環路的複雜性,以O(n)因爲當在IEnumerable<T>上使用時,CountElementAt將是O(1)而不是至少O(n))。
2

是的,這被稱爲閉包..只是定義本地變量,而不是使用索引。

一個建議是在LINQ查詢結束使用ToList,這樣選擇是在計數的每個電話和ElementAt的

var array = collection.Select(() => .....).ToList(); 

while (index < array.Count()) 
{ 
     int index_dup = index 
    this.CurrentDispatcher.Invoke(new Action(() => 
    { 
     ... 
     object a = array.ElementAt(index_dup) 
     ... 
    }), DispatcherPriority.Input); 

    index++; 
} 
+1

由於OP顯式聲明「代碼是安全的,因爲Invoke是同步的...」,所以Closure與問題無關。 ToList可能是解決方案。 –

+0

@AlexeiLevenkov是的,你是正確的Invoke是同步的,所以只有在委託執行後,控制纔會返回。在BeginInvoke的情況下,Closure會是問題。 。 – Viru

3

當你從評論瞭解您的查詢將被每次執行評估你致電array.Countarray.ElementAt(index)
每次執行都可能返回不同的結果,它可能是異常的原因。
使用.ToList()擴展方法,其中「兌現」的查詢結果List<T>,可安全使用

List array = collection.Select(() => .....).ToList(); 

因爲你的代碼只是循環查詢的結果,可以考慮使用@阿列克謝的建議,循環計數一次

IEnumerable array = collection.Select(() => .....); 

foreach(var item in array) 
{ 
    this.CurrentDispatcher.Invoke(new Action(() => 
    { 
     //... 
     object a = item; 
     //... 
    }), DispatcherPriority.Input); 
} 
相關問題