2012-03-31 75 views
1

完全懶惰的單身,我有以下代碼實現我一般單供應商:如何創建泛型

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

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

    class SingletonCreator 
    { 
      static SingletonCreator() 
      { 
      } 

      internal static readonly T instance = new T(); 
    } 
} 

這個樣本是從2篇拍攝,我合併的代碼讓我我想要的東西:

http://www.yoda.arachsys.com/csharp/singleton.html and http://www.codeproject.com/Articles/11111/Generic-Singleton-Provider

這是我嘗試使用上面的代碼:

public class MyClass 
{ 
    public static IMyInterface Initialize() 
    { 
      if (Singleton<IMyInterface>.Instance == null // Error 1 
      { 
       Singleton<IMyInterface>.Instance = CreateEngineInstance(); // Error 2 
       Singleton<IMyInterface>.Instance.Initialize(); 
      } 

      return Singleton<IMyInterface>.Instance; 
    } 
} 

和接口:

public interface IMyInterface 
{ 
} 

Error 1的錯誤是:

'MyProject.IMyInterace' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'MyProject.Singleton<T>' 

Error 2錯誤是:

Property or indexer 'MyProject.Singleton<MyProject.IMyInterface>.Instance' cannot be assigned to -- it is read only 

我該如何解決這個問題,以便它符合上面提到的兩篇文章?任何其他想法或建議表示讚賞。

我的實現是否打破Singleton模式?

+0

單身已死; [生命期/範圍應該由依賴注入容器來處理](http://stackoverflow.com/questions/4484619/does-mef-lend-any-value-to-the-singleton-pattern/4484889#4484889)。 – 2012-03-31 12:18:27

+0

當然。創建和控制單個對象的生命週期是單身人士的責任,但是您正在嘗試爲該類別外的單身人員類的實例屬性賦值。從我看到的依賴注入和基於接口的編程中,你真正想要做什麼。 Singleton只在嘗試使用sparce資源(例如數據庫連接)時非常有用,並且應謹慎使用(甚至可以避免) – 2012-03-31 12:22:12

+0

我正在嘗試爲我的web mvc應用程序創建引擎,它處理我需要的所有內容,依賴注入,我只希望這個實例的一個實例存在。 – 2012-03-31 12:36:28

回答

2

基本上,你已經給你的singleton類和new()約束賦予了一個類約束。

當寫

Singleton<IMyInterface> 

您使用的接口類型爲T,違反您定義的類型約束。

對於錯誤2,

Singleton<IMyInterface>.Instance = CreateEngineInstance(); 

你想分配一個值的只讀屬性。所以你需要在你的Instance屬性上定義一個setter來讓這行工作。

更新

東西沿着這些線路應該爲你做:

public sealed class Singleton 
{ 
    private static Hashtable bindings = new Hashtable(); 
    private static Hashtable instances = new Hashtable(); 

    private static void checkType(Type requested, Type bound) 
    { 
     if (requested.IsValueType) 
      throw new Exception("Cannot bind a value type to a reference type"); 

     // also check type inheritance and other things... 
    } 

    private static void checkBinding(Type requested) 
    { 
     if (!(bindings.ContainsKey(requested))) 
      throw new Exception(String.Format("Type {0} was not bound !", requested.FullName)); 
    } 

    public static void Bind<T, U>() where U : class, new() 
    { 
     checkType(typeof(T), typeof(U)); 
     bindings[typeof(T)] = typeof(U); 
    } 

    public static T GetInstance<T>() 
    { 
     Type requested = typeof(T); 
     Type bound = (Type) bindings[requested]; 

     checkBinding(requested); 

     if (!instances.ContainsKey(requested)) { 
      // We know that type "bound" was set with a new() class constraint 
      instances[requested] = (T) Activator.CreateInstance(bound); 
     } 

     return (T) instances[requested]; 
    } 
} 

然後,您可以寫:

Singleton.Bind<IMyInterface, MyClass>(); 
IMyInterface instance = Singleton.GetInstance<IMyInterface>(); 

如果你想走得更遠,你也可以指定由此提供程序創建的對象的生命週期,以便您可以使用單例,或讓提供程序返回eac的新對象h呼叫等等。

您還應該看看依賴注入模式,它看起來接近您想要實現的目標,並且還查看已經執行此操作的現有DI框架(NInject,Nhibernate)等等。

2

當然,你有一個問題。你的通用是假設採取類,而不是接口。

internal static readonly T instance = new T(); 

您的代碼假設要創建該類的實例,但不能實例化接口類型。

所以,如果你需要某種類型的充當singletone,你應該寫:

Singleton<MyInterface>.Instance 

其中

public class MyInterface : IMyInterface { } 

然後,你不需要有任何「如果」在你的代碼,因爲Singleton負責將瞬間對象保持爲一個實例。

與問題無關:目前Singletone's被許多開發者視爲'代碼嗅覺',所以一般來說你必須避免它們。嘗試不考慮Singletone的應用程序。

+0

我有一個引擎,我想在整個mvc應用程序中使用。它處理像依賴注入,獲取當前用戶等東西。這就是爲什麼我想要一個引擎。 – 2012-03-31 13:51:44

+0

考慮到你的評論,我會說 - 你在MVC應用程序中做了一些真正錯誤的事情。如果你在應用程序中有IoC容器,他們中的很多人都有InSingletoneScope()策略來創建對象。你不需要創建你自己的。 – 2012-03-31 15:46:12