CA2000 当引用保存在 ConcurrentDictionary 中时发出警告
CA2000 Dispose warning when reference held in a ConcurrentDictionary
我有一个 parent class,其中包含 child class 的集合。 class 都是 IDisposable
。我收到警告 CA2000 ("Call Dispose on object ... before all references to it are out of scope."),但我不想 Dispose()
它在创建它的同一方法调用中,因为 child 寿命长。我在 parent class 中保留了对它的引用。如果该引用位于 Dictionary
或 ConcurrentBag
中,则一切正常。如果引用在 ConcurrentDictionary
中,则会列出 CA2000。
据我所知,我正在正确实施 IDisposable
。也许我迭代并发集合和调用 Dispose()
的方式可以改进,尽管我怀疑这不是警告的来源。
这是 compiler/warnings 中的错误,还是我可以通过代码实现合规性?我的理论是它是用于添加引用的函数语法,但我不确定。
以下示例重现警告,child1
和 child3
正常,但 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
}
这不是您的代码中的问题,而是您所使用的 FxCop 版本的疏忽。
这已在最新版本中修复。参见 https://github.com/dotnet/roslyn-analyzers/issues/3082
我有一个 parent class,其中包含 child class 的集合。 class 都是 IDisposable
。我收到警告 CA2000 ("Call Dispose on object ... before all references to it are out of scope."),但我不想 Dispose()
它在创建它的同一方法调用中,因为 child 寿命长。我在 parent class 中保留了对它的引用。如果该引用位于 Dictionary
或 ConcurrentBag
中,则一切正常。如果引用在 ConcurrentDictionary
中,则会列出 CA2000。
据我所知,我正在正确实施 IDisposable
。也许我迭代并发集合和调用 Dispose()
的方式可以改进,尽管我怀疑这不是警告的来源。
这是 compiler/warnings 中的错误,还是我可以通过代码实现合规性?我的理论是它是用于添加引用的函数语法,但我不确定。
以下示例重现警告,child1
和 child3
正常,但 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
}
这不是您的代码中的问题,而是您所使用的 FxCop 版本的疏忽。
这已在最新版本中修复。参见 https://github.com/dotnet/roslyn-analyzers/issues/3082