提问人:Maxim Gershkovich 提问时间:6/6/2011 更新时间:1/18/2019 访问量:7480
ObservableCollection<T>中的 BlockReentrancy
BlockReentrancy in ObservableCollection<T>
问:
有人可以向我解释该方法的目的是什么吗?BlockReentrancy
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
}
但这似乎并没有为我澄清目的是什么。有人愿意解释吗?
答:
这是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"));
}
}
修改集合前检查、ClearItems
InsertItem
MoveItem
RemoveItem
SetItem
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)
{
}
评论
StackOverflowException
InvalidOperationException
重入是指方法直接或间接执行某些操作,导致该方法再次被调用,可能是递归方式。在这种情况下,如果要防止从处理程序中更改集合,则应在 OnCollectionChanged 委托中使用 using 块;尝试更改它将引发异常。如果未使用它,则任何修改集合的尝试都会导致再次调用 OnCollectionChanged。
一个实现,所以它有一个事件。如果存在此事件的订阅者,则他们可以在集合已在通知过程中时进一步修改集合。由于事件会准确跟踪更改的内容,因此这种交互可能会变得非常混乱。ObservableCollection
INotifyCollectionChanged
CollectionChanged
CollectionChanged
因此,作为特殊情况,允许事件的单个订阅者从其处理程序修改集合。但是,如果事件有两个或多个订阅者,则不允许从处理程序修改集合。ObservableCollection
CollectionChanged
CollectionChanged
CollectionChanged
用于实现此逻辑的一对方法。在方法的开头使用 ,并用于修改集合的所有方法。BlockReentrancy
CheckReentancy
BlockReentrancy
OnCollectionChanged
CheckReentancy
评论
以下是 BlockReentrancy 背后的代码。CheckReentrancy 在 ObservableCollection 实现中每个集合修饰符方法的开头调用。
/// <summary>
/// Disallow reentrant attempts to change this collection. E.g. an event handler
/// of the CollectionChanged event is not allowed to make changes to this collection.
/// </summary>
/// <remarks>
/// typical usage is to wrap e.g. a OnCollectionChanged call with a using() scope:
/// <code>
/// using (BlockReentrancy())
/// {
/// CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, item, index));
/// }
/// </code>
/// </remarks>
protected IDisposable BlockReentrancy()
{
_blockReentrancyCount++;
return EnsureMonitorInitialized();
}
/// <summary> Check and assert for reentrant attempts to change this collection. </summary>
/// <exception cref="InvalidOperationException"> raised when changing the collection
/// while another collection change is still being notified to other listeners </exception>
protected void CheckReentrancy()
{
if (_blockReentrancyCount > 0)
{
// we can allow changes if there's only one listener - the problem
// only arises if reentrant changes make the original event args
// invalid for later listeners. This keeps existing code working
// (e.g. Selector.SelectedItems).
if (CollectionChanged?.GetInvocationList().Length > 1)
throw new InvalidOperationException(SR.ObservableCollectionReentrancyNotAllowed);
}
}
private SimpleMonitor EnsureMonitorInitialized()
{
return _monitor ?? (_monitor = new SimpleMonitor(this));
}
(版权所有 (c) .NET Foundation 和贡献者)
评论
BlockReëntrancy
using (BlockReentrancy()) {}
OnCollectionChanged