ObservableCollection中的块重入

发布于 2024-11-13 21:40:49 字数 442 浏览 4 评论 0原文

有人可以向我解释一下 ObservableCollectionBlockReentrancy 方法的用途吗?

MSDN 显示以下内容作为示例:

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

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

但这似乎并不为我澄清目的是什么。有人愿意解释一下吗?

Could someone please be kind enough to explain to me what the purpose of the BlockReentrancy Method is in the ObservableCollection<T> ?

MSDN shows the following as an example:

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

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

But this doesn't seem to clarify for me what the purpose is. Anyone care to explain?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

萝莉病 2024-11-20 21:40:49

ObservableCollection 实现 INotifyCollectionChanged,因此它有一个 CollectionChanged 事件。如果有此事件的订阅者,他们可以在集合已处于通知过程中时进一步修改集合。由于 CollectionChanged 事件准确跟踪更改的内容,因此这种交互可能会变得非常混乱。

因此,作为一种特殊情况,ObservableCollection 允许 CollectionChanged 事件的单个订阅者从其处理程序修改集合。但如果 CollectionChanged 事件有两个或更多订阅者,它不允许CollectionChanged 处理程序修改集合。

BlockReentrancyCheckReentancy 这对方法用于实现此逻辑。 BlockReentrancy 用于 OnCollectionChanged 方法的开头,CheckReentancy 用于修改集合的所有方法。

An ObservableCollection implements INotifyCollectionChanged and so it has a CollectionChanged event. If there is a subscriber to this event, they could further modify the collection while the collection is already in the process of notification. Since the CollectionChanged event keeps track of exactly what changed, this interaction can get very messy.

As a result, the ObservableCollection allows, as a special case, a single subscriber of the CollectionChanged event to modify the collection from its handler. But it disallows modifying the collection from the CollectionChanged handler if there are two or more subscribers to the CollectionChanged event.

The pair of methods BlockReentrancy and CheckReentancy are used to implement this logic. The BlockReentrancy is used at the start of the OnCollectionChanged method and CheckReentancy is used in all methods that modify the collection.

枕花眠 2024-11-20 21:40:49

这是 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"));
    }
}

诸如 ClearItemsInsertItem、< code>MoveItem、RemoveItemSetItem 在修改集合之前检查 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)
{
}

This is implementation of BlockReentrancy()

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

There is another method CheckReentrancy()

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

Such methods as ClearItems, InsertItem, MoveItem, RemoveItem, SetItem check CheckReentrancy() before modifying collection.

So the code below guarantees that collection will not be changed inside of using, but only if there is more than one handler subscribed to CollectionChanged event.

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

This example demonstrates effect of 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)
{
}
执手闯天涯 2024-11-20 21:40:49

重入是指一个方法直接或间接执行某些操作,导致该方法被再次调用(可能是递归调用)。在这种情况下,如果您想防止在处理程序中更改集合,则应在 OnCollectionChanged 委托内部使用 using 块;尝试更改它会引发异常。如果您没有使用它,则任何修改集合的尝试都会导致 OnCollectionChanged 再次被调用。

Reentrancy is when a method does something directly or indirectly that causes that method to be invoked again, possibly recursively. In this case, the using block should be used inside the OnCollectionChanged delegate if you want to prevent the changing of the collection from within the handler; attempts to change it will throw an exception. If you didn't use it, then any attempts to modify the collection would cause OnCollectionChanged to be called again.

妞丶爷亲个 2024-11-20 21:40:49

下面是 代码 位于 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 基金会和贡献者)

Below is the code behind BlockReentrancy. CheckReentrancy is called at the start of each collection modifier method in the implementation of 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));
    }

(Copyright (c) .NET Foundation and Contributors)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文