Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 可观测采集中的块重入性<;T>;_C#_.net_Events_Collections_Observablecollection - Fatal编程技术网

C# 可观测采集中的块重入性<;T>;

C# 可观测采集中的块重入性<;T>;,c#,.net,events,collections,observablecollection,C#,.net,Events,Collections,Observablecollection,请有人向我解释一下BlockReentrancy方法在observeCollection中的作用是什么 显示以下内容作为示例: //The typical usage is to wrap an OnCollectionChanged call within a using scope, as in the following example: using (BlockReentrancy()) { // OnCollectionChanged call } 但这似乎并没有为我阐明目

请有人向我解释一下
BlockReentrancy
方法在
observeCollection
中的作用是什么

显示以下内容作为示例:

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

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

但这似乎并没有为我阐明目的是什么。有人想解释一下吗?

这是
blockreentancy()的实现。

还有另一种方法
checkreentancy()

在修改集合之前,诸如
ClearItems
InsertItem
MoveItem
RemoveItem
SetItem
检查
CheckReentrancy()

    /// <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));
    }
因此,下面的代码保证不会使用在
内部更改集合,但只有在订阅了多个处理程序的
CollectionChanged
事件时才会更改集合

using BlockReentrancy())
{
    CollectionChanged(this, e);
}
此示例演示了
blockreentancy()


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

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

因此,
observateCollection
作为特例,允许
CollectionChanged
事件的单个订户从其处理程序修改集合。但是如果有两个或多个订阅者
CollectionChanged
事件,则不允许从
CollectionChanged
处理程序修改集合

using BlockReentrancy())
{
    CollectionChanged(this, e);
}
这对方法
blockreentancy
CheckReentancy
用于实现此逻辑。
blockreentancy
用于
OnCollectionChanged
方法的开头,并且
CheckReentancy
用于修改集合的所有方法。

下面是blockreentancy的后面部分。在ObservableCollection的实现中,在每个集合修饰符方法的开头调用CheckReentrancy

    /// <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基金会和贡献者)

您的演示代码将引发一个<代码> StAccOffFuffExist< <代码>,而不是<代码>无效操作异常> /代码>。在这种情况下,不检查可重入性。看到我的答案了。非常有趣的是,MSDN文档没有提到这个小事实,即CheckReentrancy只有在CollectionChanged事件连接了多个处理程序时才会阻止重入。“如果CollectionChanged事件有两个或多个订阅服务器,则不允许从CollectionChanged处理程序修改集合。”如果只有一个订阅者,但有两个工作线程在修改集合怎么办?在这种情况下,我应该使用另一个锁来锁定插入和移除等操作,并锁定OnCollectionChanged处理程序吗?宣布它为
BlockReëentrancy
除了接受的答案之外,值得一提的是
使用(blockreentancy()){}
在多线程用例中也是必需的,因为集合的更新如此频繁,以至于它干扰了
OnCollectionChanged
处理。这可能只需要一个XAML绑定,而在自定义代码中没有任何额外的显式订阅服务器。
    /// <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));
    }