2011-06-08 33 views
1

我正在研究C#的單例模式,我從msdn網站上找到了這個例子。C#中的單例模式問題

public sealed class Singleton 
{ 
    private static readonly Singleton instance = new Singleton(); 

    private Singleton(){} 

    public static Singleton Instance 
    { 
     get 
     { 
     return instance; 
     } 
    } 
} 

因爲Singleton實例是 由私人靜態成員變量 參考,並不 發生的實例,直到類是通過對實例 屬性的調用引用第一 。因此,該解決方案 實現了一種惰性 實例化屬性,如在Singleton的 Design Patterns表單中。

我不是很確定的時候會記憶將得到前甚至將其分配給

private static readonly Singleton instance 

1)它會發生在實例屬性被稱爲還是?

2)我需要強制類創建一個新的內存有時清除其內容。使用set安全嗎?

set 
{ 
instance = null; 
} 
+3

*懶實例*的形式說明了一切 – V4Vendetta 2011-06-08 11:37:30

+1

在這情況下(非常錯誤的)'集合{}'從何而來? – 2011-06-08 11:48:10

+1

你的第二個問題很有意義。 – CodesInChaos 2011-06-08 11:52:12

回答

6

在您提供的示例代碼中,將在第一次訪問該類時創建單例實例。這意味着你的例子在Instance第一次被調用的時候。

更多的洞察力,你可以在喬恩斯基特的文章Implementing the Singleton Pattern in C#尋找,查看方法4

基本上,爲了實現真正的偷懶行爲像

public sealed class Singleton 
{ 
    private static readonly Singleton instance = new Singleton(); 

    static Singleton(){} 
    private Singleton(){} 

    public static Singleton Instance 
    { 
     get { return instance; } 
    } 
} 

就足夠了。

(但不管怎麼說,全面和更好的概述,可以提及的文章中找到。)

編輯
其實,當它從提到的文章下面的實例,但不保證創建在第一次訪問時,由於BeforeFiledInit標記。你需要添加一個空的靜態構造函數,這樣保證是懶惰的。否則,該實例將在程序啓動和第一次訪問之間的某個非特定時間創建。 (.NET運行庫2.0是已知有更渴望的策略,所以你可能無法得到的偷懶行爲。)

從上述文章引用:

類型初始化的懶惰只受擔保.NET時類型沒有標記一個叫做beforefieldinit的特殊標誌。不幸的是,C#編譯器[...]標記所有沒有靜態構造函數的類型爲beforefieldinit

EDIT 2
如果你想單獨的對象進行清理,你應該包括這個功能到類Singleton本身。

刪除屬性值將有效地使您的班級不再是單身人士!想象一下,有人訪問單例並獲取單例實例。之後,您將該物業設置爲nullSingleton類的現有對象不會消失,因爲它仍然有一個參考!因此,下次您訪問Instance屬性時,將創建另一個Singleton類的實例。所以你失去了兩件事:你的對象不再是單身(因爲你有兩個同時存在的實例),並且內存也沒有被清除。

0

它說,在您發佈的報價:直到 類首先由 呼叫參考實例屬性

所以

的實例不會發生......每當你請致電.Instance,或者之前的某個時間點。

+0

問題是這個報價不能被規範保證。這導致了「或者在某個時刻之前」部分。 – CodesInChaos 2011-06-08 11:50:11

0

第一次訪問靜態成員之前,以及靜態構造函數(如果有)被調用之前,會初始化靜態成員。

Read more on MSDN

3

C#的規範說:一類

10.5.5.1靜態字段初始化

在靜磁場用變量初始化對應於在文本執行的任務序列它們出現在類聲明中的順序。如果類中存在靜態構造函數(第10.12節),則在執行靜態構造函數之前立即執行靜態字段初始化函數。否則,靜態字段初始值設定項會在第一次使用該類的靜態字段之前的執行相關時間執行。

即他們只保證你得到的是它發生在instance字段被讀取之前。但它可能發生得更早。

如果你想保證它,它不跑的比屬性的第一次訪問你越早將需要添加靜態構造函數(可能爲空):

的靜態構造函數封閉類類型在給定的應用程序域中最多執行一次。靜態構造函數的執行是由應用程序域中發生以下第一個事件觸發的:
·創建了類類型的實例。
·引用了類類型的任何靜態成員。


作爲一個邊節點:我注意到,使用DI當它是很少需要使用真正的單身。簡單地告訴DI應該創建一個實例就足夠了。這是非常好的,如果你稍後決定你想要多於一個實例,那麼事實上它是一個單例不會被所有使用它的代碼烘焙。

6

當類本身被加載時,單實例實例將被加載到內存中,也就是說,可以調用它的方法開始執行。調入該類的實際行不必實際執行。這是一個非常微小的區別,但是當靜態構造函數或靜態字段初始值設定項可能會引發錯誤(您不在此處)時會創建難以調試的問題。

這在.NET 4中使用新的Lazy<T>實現得到修復。

http://msmvps.com/blogs/jon_skeet/archive/2010/01/26/type-initialization-changes-in-net-4-0.aspx

public sealed class Singleton 
{ 
    private static readonly Lazy<Singleton> lazy = 
     new Lazy<Singleton>(() => new Singleton()); 

    public static Singleton Instance { get { return lazy.Value; } } 

    private Singleton() 
    { 
    } 
} 

http://csharpindepth.com/Articles/General/Singleton.aspx