[英]Disposing a singleton instance (C#)
如果 singleton 實現 IDisposable,那么處置和重新創建實例的正確方法是什么? 一種方法是保留 _disposed 標志並在 Instance 屬性中檢查它,但我不確定這是正確的方法。 一個簡單的例子:
public sealed class Singleton: IDisposable
{
private static Singleton _instance;
private object _lock;
private UnmanagedResource _unmanaged;
private bool _disposed;
private Singleton()
{
_unmanaged = new UnmanagedResource();
_disposed = false;
_lock = new object();
}
public UnmanagedResource Unmanaged { get { return _unmanaged; } }
public static Singleton Instance
{
get
{
if (_instance == null || _disposed)
{
lock (_lock)
{
if (_instance == null || _disposed)
{
_instance = new Singleton();
}
}
}
return _instance;
}
}
public void Dispose()
{
_disposed = true;
try
{
_unmanaged.Dispose();
}
finally
{
GC.SuppressFinalize(this);
}
}
}
所以像這樣的代碼是可能的(雖然,是的,我同意,它有點違背了擁有單例的目的):
Singleton.Instance.Dispose();
Singleton.Instance.Unmanaged.UseResource(); // Unmanaged shouldn't be null.
注意: Singleton 和 IDisposable 之間的不兼容不用過分強調,我理解。 當 ApppDomain 卸載時,我需要 Dispose 方法來釋放非托管資源。 如果您對名為 Singleton 的 class 有疑問,我可以將其重命名為 LoadBalancer。 問題仍將保持不變。 這個 LoadBalancer 需要是一次性的,因為它的實例不屬於任何人,但應該妥善處理。
Singleton 和 Disposable 對象在很大程度上是不兼容的概念
單例通常在進程/ AppDomain
的整個生命周期內都是活躍的。 如果您發現自己想要Dispose
它們,那么您可能需要稍微重構您的解決方案。
如果問題與在AppDomain
卸載期間釋放資源有關,那么將釋放資源的責任與負責管理AppDomain
生命周期的 object 相同。 然后將此資源嵌入Singleton
中而不實現IDisposable
。 這將適當地分離出場景的關注點。
如果您需要更換 singleton 的實例,您應該考慮您的設計。
如果你真的認為你應該這樣做,我建議使用 2 個對象......
一個 singleton object 充當代理,並且是真正的 singleton(生命周期結束 == 進程結束)
這個 object 需要公共成員來完成您的 singleton 所能做的一切,並且需要一個私人成員持有真正的實施 object。 所有其他成員重定向到該實現的成員。
第二個object是可更換的一次性object。 make sure that only your singleton object will ever hold a reference on that... this way it doesn't matter if any consumer object holds a reference on the singleton that would prevent you from replacing the object... that ref will only point到代理
我沒有看到這將如何工作。 考慮這個假設的用例:
using (Singleton instance = Singleton.Instance)
{
// Do stuff with the instance.
}
您將如何防止多個線程同時執行此代碼? 一個線程可以調用Dispose
,而另一個線程仍在嘗試使用同一個實例。 嘗試將具有循環語義的 API 強制轉換為 singleton 概念就像試圖將方形釘子安裝在圓形支架中。
順便說一句,還有一些切向的問題值得一提。 Instance
屬性不是線程安全的。 至少您必須將_instance
標記為volatile
。 只有當您使用該模式的規范實現時。 您將永遠無法使模式安全,因為您還使用_disposed
標志作為檢查中的額外標准。 就個人而言,我會完全放棄雙重檢查鎖定模式。
也許我在問一個愚蠢的問題,但你為什么要處理 Singleton 只是為了創建一個新的? 目的不是只有一個實例嗎......
這可能是我不知道的設計問題。 在這種情況下,也許“正確的方法”是重新評估你需要你的代碼做什么以及什么樣的模式讓你到達那里。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.