У меня есть родительский класс, в котором есть коллекция дочерних классов. Оба класса IDisposable
. Я получаю предупреждение CA2000 ("Call Dispose для объекта ... до того, как все ссылки на него выйдут из области видимости."), Но я не хочу Dispose()
это в том же вызове метода, это создано, так как ребенок имеет долгую жизнь. Я держу ссылку на это в родительском классе. Если эта ссылка в Dictionary
или ConcurrentBag
, все хорошо. Если ссылка указана в ConcurrentDictionary
, в списке указывается CA2000 .
Насколько я могу судить, я правильно реализую IDisposable
. Возможно, способ, которым я итерирую параллельную коллекцию и вызываю Dispose()
, мог бы быть улучшен, хотя я подозреваю, что это не источник предупреждения.
Это ошибка в компиляторе / предупреждениях, или я могу достичь соответствие через код? Мой опыт в теории состоит в том, что это синтаксис функции, используемый для добавления ссылки, но я не уверен.
В следующем примере воспроизводится предупреждение, с 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
}