我無法正確處理包含非託管對象的ConcurrentBag
的Dispose/Finalization。運行下面的代碼(通常)會在TryTake()
的呼叫中生成ObjectDisposedException
(Cannot access a disposed object.Object name: 'The ThreadLocal object has been disposed.'.
)。包含非託管對象的ConcurrentBag的終結
大概在這種情況下,垃圾收集器在調用A的終結器之前破壞了ConcurrentBag
。我以爲只有在ConcurrentBag
本身實現了終結器的情況下才會這樣。是否在終止路徑期間不應該觸摸託管對象?
class A : IDisposable
{
private readonly ConcurrentBag<object> _collection = new ConcurrentBag<object>();
public A(string value)
{
if (value == null) throw new ArgumentNullException();
}
~A()
{
Dispose(false);
}
public void Dispose() => Dispose(true);
private void Dispose(bool disposing)
{
if (disposing) {}
object value;
while (_collection.TryTake(out value))
{
// Cleanup value
}
}
}
觸發異常:
void Main()
{
var a = new A(null);
}
下似乎解決這一具體問題,但我不能確定這是否是安全。這種情況下是否有完全安全的實現?
while (_collection.IsEmpty == false)
{
object value;
_collection.TryTake(out value);
// Cleanup value
}
你的解釋很有道理。 基於Stephen Cleary的文章,正確的實現是將非託管對象包裝在IDisposable包裝中(他稱爲「級別0」),該包裝處理考慮完成的骯髒工作。這允許更高級別的我的類A(即級別1)類只關心處理路徑並忽略最終化路徑。 – Terrence
唯一不正確的是0級對象應該從'SafeHandle'派生出來,而不是'IDisposeable',但除此之外,是的。 –