2011-06-06 96 views
23

請問有人可以向我解釋BlockReentrancy方法的用途是在ObservableCollection<T>BlockReentrancy in ObservableCollection <T>

MSDN顯示以下爲例:

//The typical usage is to wrap an OnCollectionChanged call within a using scope, as in the following example: 

using (BlockReentrancy()) 
{ 
    // OnCollectionChanged call 
} 

但是,這似乎並沒有明確對我的目的是什麼。任何人都在意解釋?

+0

發音它'BlockReëntrancy' – 2013-08-05 15:21:01

回答

26

ObservableCollection implements INotifyCollectionChanged因此它有一個CollectionChanged事件。如果有此訂單的訂閱者,他們可以在收集已經處於通知過程中的情況下進一步修改。由於CollectionChanged事件跟蹤確切地發生了什麼變化,這種交互會變得非常混亂。

因此,作爲特殊情況,ObservableCollection允許CollectionChanged事件的單個訂戶從其處理程序修改集合。但它不允許修改從CollectionChanged處理程序收集如果有兩個或多個訂戶CollectionChanged事件。

這對方法BlockReentrancyCheckReentancy用於實現此邏輯。 用於OnCollectionChanged方法的開始,CheckReentancy用於修改集合的所有方法。

+0

它用於支持線程安全嗎? – deathrace 2012-10-25 13:49:12

+0

非常有趣的是,MSDN文檔沒有提及這個小事實,只有當有多個處理程序連接到CollectionChanged事件時,CheckReentrancy纔會阻止重入。 – treaschf 2012-12-27 10:54:18

+1

「如果存在兩個或更多訂閱者到CollectionChanged事件,它不允許修改CollectionChanged處理程序的集合。」 如果只有一個訂閱者但有兩個工作線程修改集合會怎樣?在這種情況下,我應該使用另一個鎖來鎖定像Insert和Remove這樣的操作,並鎖定OnCollectionChanged處理程序嗎? – Felix 2014-01-07 02:30:58

11

這是落實BlockReentrancy()

protected IDisposable BlockReentrancy() 
{ 
    this._monitor.Enter(); 
    return this._monitor; 
} 

還有另一種方法CheckReentrancy()

protected void CheckReentrancy() 
{ 
    if ((this._monitor.Busy && (this.CollectionChanged != null)) && (this.CollectionChanged.GetInvocationList().Length > 1)) 
    { 
     throw new InvalidOperationException(SR.GetString("ObservableCollectionReentrancyNotAllowed")); 
    } 
} 

這樣的方法爲ClearItemsInsertItemMoveItemRemoveItemSetItem修改集合之前檢查CheckReentrancy()

因此,下面的代碼保證集合不會在using內部發生更改,但前提是訂閱了CollectionChanged事件的處理程序不止一個。

using BlockReentrancy()) 
{ 
    CollectionChanged(this, e); 
} 

該實施例證明BlockReentrancy()

private static void Main() 
{ 
    collection.CollectionChanged += CollectionCollectionChanged1; 
    collection.CollectionChanged += CollectionCollectionChanged2; 
    collection.Add(1); 
} 

private static void CollectionCollectionChanged1(object sender, NotifyCollectionChangedEventArgs e) 
{ 
    collection.Add(2); // this line will throw exception 
} 

private static void CollectionCollectionChanged2(object sender, NotifyCollectionChangedEventArgs e) 
{ 
} 
+1

您的演示代碼將拋出'StackOverflowException'而不是'InvalidOperationException'。在這種情況下,重入不被檢查。看到我的答案。 – 2011-06-06 03:38:43

+0

@Rick Sladkey - 你是對的。 – 2011-06-06 03:40:50

2

重入的效果時的方法做了直接或間接地導致該方法被再次調用,可能遞歸。在這種情況下,如果您想阻止處理程序中的集合更改,則應在OnCollectionChanged委託內使用using塊;試圖改變它會引發異常。如果你沒有使用它,那麼任何修改集合的嘗試都會導致OnCollectionChanged被再次調用。

相關問題