2008-12-19 85 views
19

你們認爲這是一個通用的單身人士嗎?一個通用的單身人士

using System; 
using System.Reflection; 

// Use like this 
/* 
public class Highlander : Singleton<Highlander> 
{ 
    private Highlander() 
    { 
     Console.WriteLine("There can be only one..."); 
    } 
} 
*/ 

public class Singleton<T> where T : class 
{ 
    private static T instance; 
    private static object initLock = new object(); 

    public static T GetInstance() 
    { 
     if (instance == null) 
     { 
      CreateInstance(); 
     } 

     return instance; 
    } 

    private static void CreateInstance() 
    { 
     lock (initLock) 
     { 
      if (instance == null) 
      { 
       Type t = typeof(T); 

       // Ensure there are no public constructors... 
       ConstructorInfo[] ctors = t.GetConstructors(); 
       if (ctors.Length > 0) 
       { 
        throw new InvalidOperationException(String.Format("{0} has at least one accesible ctor making it impossible to enforce singleton behaviour", t.Name)); 
       } 

       // Create an instance via the private constructor 
       instance = (T)Activator.CreateInstance(t, true); 
      } 
     } 
    } 
} 
+8

+1爲Highlander名稱;-) – 2008-12-19 11:43:50

+0

除非對鎖定對象使用volatile關鍵字,否則此鎖定技術會中斷。請參見[this](http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html) – 2011-03-03 11:12:04

+0

精細問題codereview.stackexchange.com – MPelletier 2012-03-31 17:24:31

回答

28

創建一個單獨的類的代碼只有幾行,然後開始製作一個通用的單我總是寫這些代碼行的難度。

public class Singleton 
{ 
    private Singleton() {} 
    static Singleton() {} 
    private static Singleton _instance = new Singleton(); 
    public static Singleton Instance { get { return _instance; }} 
} 

private static Singleton _instance = new Singleton(); 

行除去了鎖定的需要,因爲靜態構造函數是線程安全的。

+5

準確無誤。特別是因爲通用版本實際上並沒有給你一個singleton ... – 2008-12-19 11:46:28

5

嗯,這是不是真的單身 - 因爲你無法控制T,可以有許多T情況下,只要你喜歡。

(刪除線程的比賽;注意雙重檢查使用)

5

我刪除了我以前的答案,因爲我沒有注意到檢查非公共構造函數的代碼。但是,這是一個只在執行時執行的檢查 - 沒有編譯時間檢查,這是對它的罷工。它還依靠有足夠的訪問權限來調用非公共構造函數,這增加了一些限制。

此外,它不禁止內部構造函數 - 所以你可以結束與非單身人士。

我會親自在靜態構造函數中創建實例以實現簡單的線程安全。

基本上我不是一個粉絲 - 創建單例類很容易,而且你不應該經常這樣做。單身是用於測試的疼痛,去耦等

5

這是使用.NET 4

public class Singleton<T> where T : class, new() 
    { 
     Singleton(){} 

     private static readonly Lazy<T> instance = new Lazy<T>(()=> new T()); 

     public static T Instance { get { return instance.Value; } } 
    } 

和它的使用我的觀點是如下:

public class Adaptor 
    { 
    public static Adaptor Instance { get { return Singleton<Adaptor>.Instance;}} 
    } 
1

合併AndreasN答案,喬恩斯基特的「Fourth version - not quite as lazy, but thread-safe without using locks 「的Singleton C#實現,爲什麼不使用代碼片段來做所有的辛苦工作:

<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> 
    <CodeSnippet Format="1.0.0"> 
     <Header> 
      <Title>Singleton Class</Title> 
      <Author>TWSoft</Author> 
      <Description>Generates a singleton class</Description> 
      <SnippetTypes> 
       <SnippetType>Expansion</SnippetType> 
      </SnippetTypes> 
      <Keywords> 
       <Keyword>Singleton</Keyword> 
      </Keywords> 
      <Shortcut>singleton</Shortcut> 
     </Header> 
     <Snippet> 
      <Declarations> 
       <Literal> 
        <ID>ClassName</ID> 
        <ToolTip>Replace with class name</ToolTip> 
        <Default>MySingletonClass</Default> 
       </Literal> 
      </Declarations> 

      <Code Language="CSharp"> 
       <![CDATA[ 
       public class $ClassName$ 
       { 
        #region Singleton 
        static readonly $ClassName$ mInstance = new $ClassName$(); 

        // Explicit static constructor to tell C# compiler 
        // not to mark type as beforefieldinit 
        static $ClassName$() 
        { 
        } 

        private $ClassName$() 
        { 
        } 

        public static $ClassName$ Instance 
        { 
         get { return mInstance; } 
        } 
       #endregion 
       } 
       ]]> 
      </Code> 
     </Snippet> 
    </CodeSnippet> 
</CodeSnippets> 

然後,您可以將其保存到.snippt文件中,並將其添加到VS IDE(工具 - >代碼片段管理器)。

-1

我不認爲使用泛型對單身人士有用。因爲你總是可以創建多個實例,所以它是而不是按定義是一個單例。如果你需要一個懶惰的單身人士,並要求它是一個真正的單身一個簡單的解決方案(基於亞歷山大的例子)

public sealed class Adaptor 
{ 
    private static readonly Lazy<Adaptor> instance = new Lazy<Adaptor>(() => new Adaptor()); 

    public static Adaptor Instance { get { return instance.Value; } } 

    private Adaptor() { } 
} 

不能正確重構爲一個單獨的通用單這一點。

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

0

有一個通用的單廠出了問題,因爲它是通用的,你不用管被實例化的singleton類型,所以你可以永遠無法保證該實例創建將是應用程序中的唯一實例。

因此,你不能創建一個通用的單體工廠 - 它破壞了模式本身。