简体   繁体   English

CA2000 在 ConcurrentDictionary 中保存引用时处理警告

[英]CA2000 Dispose warning when reference held in a ConcurrentDictionary

I have a parent class that has a collection of child classes.我有一个包含子类集合的父类。 Both classes are IDisposable .这两个类都是IDisposable I am receiving warning CA2000 ("Call Dispose on object ... before all references to it are out of scope."), but I don't want to Dispose() it in the same method call it's created, as the child has a long lifetime.我收到警告CA2000 (“在对象上调用 Dispose ......在对它的所有引用超出范围之前。”),但我不想在它创建的相同方法调用中Dispose()它,因为孩子有漫长的一生。 I'm keeping a reference to it in the parent class.我在父类中保留对它的引用。 If that reference is in a Dictionary or a ConcurrentBag , all is well.如果该引用在DictionaryConcurrentBag ,则一切正常。 If the reference is in a ConcurrentDictionary , CA2000 is listed.如果引用在ConcurrentDictionary ,则列出CA2000

As far as I can tell I'm implementing IDisposable correctly.据我所知,我正在正确实施IDisposable Perhaps the way I'm iterating a concurrent collection and calling Dispose() could be improved, although I suspect that's not the source of the warning.也许我迭代并发集合和调用Dispose()可以改进,尽管我怀疑这不是警告的来源。

Is this a bug in the compiler/warnings, or can I achieve compliance through code?这是编译器/警告中的错误,还是我可以通过代码实现合规性? My stab at a theory is that it's being of the function syntax used to add the reference, but I'm not sure.我的一个理论是它是用于添加引用的函数语法,但我不确定。

The following example reproduces the warning, with child1 and child3 being fine, but child2 producing the warning, when the only difference is the container type:下面的示例再现警告,与child1child3感很好,但child2产生警告,当唯一的区别是,容器类型:

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;

public class ParentDisposable : IDisposable
{
    private readonly Dictionary<string, ChildDisposable> dictionary = new Dictionary<string, ChildDisposable>();
    private readonly ConcurrentDictionary<string, ChildDisposable> concurrentDictionary = new ConcurrentDictionary<string, ChildDisposable>();
    private readonly ConcurrentBag<ChildDisposable> concurrentBag = new ConcurrentBag<ChildDisposable>();

    public void CreateChild()
    {
        // I want to create these disposable children, use them beyond the lifetime of this method call, and dispose of them when this parent class is disposed of
        var child1 = new ChildDisposable(); // No warning
        var child2 = new ChildDisposable(); // Warning CA2000  Call System.IDisposable.Dispose on object created by 'new ChildDisposable()' before all references to it are out of scope.
        var child3 = new ChildDisposable(); // No Warning
        this.dictionary.Add("key", child1);
        this.concurrentDictionary.AddOrUpdate("key", child2, (k, v) => child2);
        this.concurrentBag.Add(child3);
    }

    #region IDisposable Pattern
    private bool disposedValue = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposedValue)
        {
            if (disposing)
            {
                foreach (var key in this.dictionary.Keys)
                {
                    this.dictionary[key].Dispose();
                }

                foreach (var key in this.concurrentDictionary.Keys)
                {
                    this.concurrentDictionary[key].Dispose();
                }

                foreach (var child in this.concurrentBag)
                {
                    child.Dispose();
                }
            }

            this.disposedValue = true;
        }
    }

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }
    #endregion IDisposable Pattern
}

public class ChildDisposable : IDisposable
{
    private EventWaitHandle waitObject = new EventWaitHandle(false, EventResetMode.AutoReset);

    #region IDisposable Pattern
    private bool disposedValue = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposedValue)
        {
            this.waitObject.Dispose();
            this.disposedValue = true;
        }
    }

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }
    #endregion IDisposable Pattern
}

This is not a problem in your code, it's an oversight in the version of FxCop you are using.这不是您代码中的问题,而是您使用的 FxCop 版本的疏忽。

This has been fixed in the latest version.这已在最新版本中修复。 See https://github.com/dotnet/roslyn-analyzers/issues/3082https://github.com/dotnet/roslyn-analyzers/issues/3082

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM