2012-03-31 2 views
1

Ich habe den folgenden Code Umsetzung meiner generic Singleton Anbieter:Wie ein vollständig träges Singleton für Generika schaffen

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(); 
    } 
} 

Diese Probe von 2 Artikel genommen wurde und ich zusammen den Code mir zu bekommen, was ich wollte:

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

Dies ist, wie ich versuchte, über den Code zu verwenden:

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; 
    } 
} 

und die Schnittstelle:

public interface IMyInterface 
{ 
} 

Der Fehler bei Error 1 ist:

'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>' 

Der Fehler bei Error 2 ist:

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

Wie kann ich das beheben, so dass es mit den 2 oben genannten Artikeln übereinstimmt? Irgendwelche anderen Ideen oder Vorschläge werden geschätzt.

Durchbricht meine Implementierung das Singleton-Muster?

+0

Singleton ist tot; [Lifetime/Scoping sollte in diesen Tagen durch Dependency-Injection-Container gehandhabt werden] (http://stackoverflow.com/questions/4484619/does-mef-lend-any-value-to-the-singleton-pattern/4484889#4484889). –

+0

Absolut. Es liegt in der Verantwortung des Singletons, den Lebenszyklus eines einzelnen Objekts zu erstellen und zu steuern, aber Sie versuchen, der Instanzeigenschaft der Singleton-Klasse OUTSIDE dieser Klasse einen Wert zuzuweisen. Was Sie wirklich versuchen, was ich sehe, ist die Abhängigkeitsinjektion und die Schnittstellen-basierte Programmierung. Singleton ist nur nützlich, wenn Sie versuchen, Sparce-Ressourcen (Datenbankverbindung zum Beispiel) zu verwenden, und sollte mit Vorsicht verwendet werden (sogar vermieden) –

+0

Ich versuche, eine Engine für meine Web-Mvc-App zu erstellen, es behandelt alles, was ich brauche , Abhängigkeitsinjektion, und ich möchte nur 1 Instanzen dieser Instanz existieren. –

Antwort

2

Sie haben Ihrer Singleton-Klasse zusammen mit der new() - Einschränkung eine Klasseneinschränkung zugewiesen.

Wenn

Singleton<IMyInterface> 

Schreiben Sie einen Schnittstellentyp als T verwenden, die die Typeinschränkung Sie definiert verletzt.

Für Fehler 2,

Singleton<IMyInterface>.Instance = CreateEngineInstance(); 

Sie versuchen, einen Wert in eine schreibgeschützte Eigenschaft zuweisen. Sie müssen daher einen Setter für Ihre Instance-Eigenschaft definieren, damit diese Linie funktioniert.

aktualisieren

Etwas in dieser Richtung sollte es für Sie tun:

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]; 
    } 
} 

Sie könnten dann schreiben:

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

Wenn Sie weiter gehen wollen, können Sie auch Geben Sie den Lebenszyklus der Objekte an, die von diesem Anbieter erstellt wurden, sodass Sie Singletons verwenden können oder der Provider ein neues Objekt für eac zurückgeben kann h Anruf und so weiter.

Sie sollten sich auch das Dependency Injection-Muster ansehen, das nahe an dem zu sein scheint, was Sie erreichen möchten, und auch vorhandene DI-Frameworks (NInject, Nhibernate), die dies und noch viel mehr tun.

2

Sicher, Sie haben ein Problem dort. Du generic soll eine Klasse nehmen, keine Schnittstelle.

internal static readonly T instance = new T(); 

Ihr Code angenommen, um eine Instanz dieser Klasse zu erstellen, konnten Sie Interface-Typ nicht instanziieren.

Also, wenn Sie irgendeine Art zu handeln, wie Singletone benötigen, sollten Sie schreiben:

Singleton<MyInterface>.Instance 

wo

public class MyInterface : IMyInterface { } 

Dann müssen Sie müssen keine 'wenn' in Sie Code , da es Singleton verantwortlich ist, ein Objekt zu instantiieren und es als nur eine Instanz zu behalten.

Nicht im Zusammenhang mit Frage: Derzeit Singletones werden von vielen Entwicklern als "Code-Geruch", so im Allgemeinen müssen Sie sie vermeiden. Versuchen Sie, Ihre Anwendung ohne Singletone zu denken.

+0

Ich habe eine Engine, die ich in meiner MVC-App verwenden möchte. Es behandelt Dinge wie Dependency-Injection, den aktuellen Benutzer zu bekommen, usw. Deshalb möchte ich einen einzigen der Engine. –

+0

Unter Berücksichtigung Ihres Kommentars würde ich sagen - Sie machen etwas wirklich falsch in Ihrer MVC-Anwendung. Wenn Sie einen IoC-Container in der App verwenden, verfügen viele von ihnen über die InSingletoneScope() - Strategie der Objekterstellung. Sie müssen nicht Ihre eigenen erstellen. –