46 Stimmen

Singleton mit Parametern

Ich brauche eine Singleton-Klasse, die mit einigen Argumenten instanziiert wird. Die Art und Weise, wie ich es jetzt tue, ist:

class SingletonExample
{
     private SingletonExample mInstance;
     //other members... 
     private SingletonExample()
     {

     } 
     public SingletonExample Instance
     {
         get
         {
              if (mInstance == null)
              {
                  throw new Exception("Object not created");
              }
              return mInstance;
         }
     }

     public void Create(string arg1, string arg2)
     {
         mInstance = new SingletonExample();
         mInstance.Arg1 = arg1;
         mInstance.ObjectCaller = new ObjectCaller(arg2);
         //etc... basically, create object...
     } 
}

Die Instanz wird "spät" erstellt, was bedeutet, dass ich beim Start der Anwendung nicht alle benötigten Argumente habe.

Im Allgemeinen mag ich es nicht, eine Reihenfolge von Methodenaufrufen zu erzwingen, aber hier sehe ich keine andere Möglichkeit. Das IoC würde es auch nicht lösen, denn wo ich es im Container registrieren kann, kann ich auch Create() aufrufen...

Halten Sie dies für ein gutes Szenario? Haben Sie eine andere Idee?

bearbeiten : I wissen dass das, was ich als Beispiel geschrieben habe, nicht thread-sicher ist, thread-sicher ist nicht Teil der Frage

0 Stimmen

Das ist no ein Singleton. Wo ist der gegenseitige Ausschluss? (d.h. lock ). plus Ihre getter für die Instanz sollte die Instanz erzeugen, nicht den Ctor - das ist der Sinn der Sache.

0 Stimmen

Ich stimme mit RPM1984 überein, dass es sich nicht um ein Singleton handelt. Können sich Ihre Argumente ändern oder bleiben sie während der gesamten Lebensdauer Ihrer Anwendung gleich? Ein Singleton sollte nicht von einer Variablen abhängen, es könnte von der Konfiguration oder einem anderen Singleton abhängen. Wie auch immer, denken Sie wirklich über Ihren Entwurf nach und fragen Sie sich, ob Sie ein Singleton brauchen. Eine übermäßige Verwendung von Singletons ist wirklich schlecht für Ihr Design.

1 Stimmen

Es ist schon ein Einzelfall, glauben Sie mir :) die getter kann die Instanz nicht erstellen, da es keine Argumente hat - es könnte, aber es ist einfach bequemer, es so zu schreiben. Und die Argumente, einmal erhalten, ändern sich nicht.

55voto

annakata Punkte 72408

Singleton ist hässlich, aber da der Benutzer whateva nicht die Mühe auf sich nehmen kann, seinen eigenen Code zu korrigieren...

public class Singleton 
{ 
    private static Singleton _instance = null; 

    private static Object _mutex = new Object();

    private Singleton(object arg1, object arg2) 
    { 
        // whatever
    } 

    public static Singleton GetInstance(object arg1, object arg2)
    { 
        if (_instance == null) 
        { 
          lock (_mutex) // now I can claim some form of thread safety...
          {
              if (_instance == null) 
              { 
                  _instance = new Singleton(arg1, arg2);
              }
          } 
        }

        return _instance;
    }
}  

Skeet hat schon vor Jahren darüber gebloggt, ich glaube, es ist ziemlich zuverlässig. Keine Ausnahmen notwendig, Sie sind nicht in das Geschäft der Erinnerung, welche Objekte sollen Singletons und Umgang mit dem Fallout, wenn Sie es falsch.

Bearbeiten: die Typen sind nicht relevant verwenden, was Sie wollen, object wird hier nur der Einfachheit halber verwendet.

0 Stimmen

Nun, DAS ist ein Singleton, nicht, dass ich sie explizit verwenden (ich lasse DI sie tun, und nur für Dinge wie Protokollierung). +1

0 Stimmen

Ich gehe mal davon aus, dass whateva beschlossen hat, eine funktionell richtige Antwort herunterzustufen. Los, Team.

0 Stimmen

Nein, hat er nicht (siehe sein Profil). Wie auch immer, das ganze Gerede über Singles hat mich müde gemacht, ich gehe jetzt ins Bett :)

36voto

Erich Kitzmueller Punkte 35336

Ein Singleton mit Parametern riecht für mich verdächtig.

Betrachten Sie die Antwort von whateva und den folgenden Code:

Singleton x = Singleton.getInstance("hello", "world");
Singleton y = Singleton.getInstance("foo", "bar");

Offensichtlich funktioniert x==y und y mit den Erstellungsparametern von x, während die Erstellungsparameter von y einfach ignoriert werden. Die Ergebnisse sind wahrscheinlich... zumindest verwirrend.

Wenn Sie wirklich das Gefühl haben, dass Sie es tun müssen, machen Sie es so:

class SingletonExample
{
     private static SingletonExample mInstance;
     //other members... 
     private SingletonExample()
     {  // never used
        throw new Exception("WTF, who called this constructor?!?");
     }
     private SingletonExample(string arg1, string arg2)
     {
         mInstance.Arg1 = arg1;
         mInstance.ObjectCaller = new ObjectCaller(arg2);
         //etc... basically, create object...    
     } 
     public static SingletonExample Instance
     {
         get
         {
              if (mInstance == null)
              {
                  throw new Exception("Object not created");
              }
              return mInstance;
         }
     }

     public static void Create(string arg1, string arg2)
     {
         if (mInstance != null)
         {
             throw new Exception("Object already created");
         }
         mInstance = new SingletonExample(arg1, arg2);             
     } 
}

Fügen Sie in einer Multithreading-Umgebung Synchronisierung hinzu, um Race Conditions zu vermeiden.

7 Stimmen

-Ein Singleton ist eine Klasse, die es nur erlaubt, eine einzige Instanz von sich selbst zu erstellen, und normalerweise einen einfachen Zugriff auf diese Instanz ermöglicht. Wenn auf dieselbe Instanz für alle Anfragen mit demselben Parameter zugegriffen werden soll, ist das Fabrikmuster angemessen.

12 Stimmen

Massimiliano, in meiner Lösung können Sie create genau einmal aufrufen. Und ich denke, mein Text macht deutlich genug, dass ich auch nicht wirklich mit der Idee der parametrisierten Singletons einverstanden bin.

1 Stimmen

@Massimiliano Peluso - jetzt dass ist eine nützliche Beobachtung - eine Fabrik... was ich bin nach ist eigentlich eine Mischung aus Singleton/Fabrik, die eigentlich bis zu IoC kocht... Wie auch immer, ich denke, ich habe meine Antwort jetzt. Danke

6voto

Bogdan Maxim Punkte 5606

Bessere Antwort:

  1. Erstellen Sie eine Schnittstelle: ISingleton (mit den von Ihnen gewünschten Aktionen)

  2. Und Ihr Typ: Singleton : ISingleton

  3. Angenommen, Sie haben Zugriff auf einen UnityContainer:

IUnityContainer _singletonContainer = new UnityContainer(); // or whatever code to initialize the container

  1. Wenn Sie bereit sind, Ihren Typ zu erstellen, verwenden Sie (vorausgesetzt, Sie verwenden Unity für DI):

_singletonContainer.RegisterType(typeof(ISingleton), new Singleton(params));

  1. Wenn Sie das Singleton greifen wollen, verwenden Sie einfach:

var localSingletonVar = _singletonContainer.Resolve<ISingleton>();

Hinweis: Wenn der Container keinen Typ hat, der für die ISingleton-Schnittstelle registriert ist, sollte er entweder eine Ausnahme auslösen oder null zurückgeben.

Alte Antwort:

public class Singleton
{

    private static Singleton instance = null;

    private Singleton(String arg1, String arg2)
    {
    }

    public static Singleton getInstance(String arg1, String arg2)
    {
        if (instance != null)
        {
            throw new InvalidOperationException("Singleton already created - use getinstance()");
        }
        instance = new Singleton(arg1, arg2);
        return instance;
    }

    public static Singleton getInstance()
    {
        if (instance == null)
            throw new InvalidOperationException("Singleton not created - use GetInstance(arg1, arg2)");
        return instance;
    }
}

Ich würde mit etwas ähnliches gehen (Sie könnten überprüfen müssen, wenn Instanz auch erstellt wurde), oder, wenn Ihr DI-Container unterstützt Ausnahmen auf nicht registrierte Typen zu werfen, würde ich mit dem gehen.

ATTN: Nicht thread-sicherer Code :)

2voto

Johnny Punkte 21

Die von annakata angebotene Lösung mit doppelt sperrenden Singletons funktioniert nicht immer auf allen Plattformen. Es gibt einen Fehler in diesem Ansatz, der gut dokumentiert ist. Verwenden Sie diesen Ansatz nicht oder Sie werden mit Problemen enden.

Die einzige Möglichkeit, dieses Problem zu lösen, ist die Verwendung des Schlüsselworts volatile, z. B.

private static volatile Singleton m_instance = null;

Dies ist der einzig sichere Ansatz.

1voto

Brick Punkte 59
/// <summary> Generic singleton with double check pattern and with instance parameter </summary>
/// <typeparam name="T"></typeparam>
public class SingleObject<T> where T : class, new()
{
    /// <summary> Lock object </summary>
    private static readonly object _lockingObject = new object();

    /// <summary> Instance </summary>
    private static T _singleObject;

    /// <summary> Protected ctor </summary>
    protected SingleObject()
    {
    }

    /// <summary> Instance with parameter </summary>
    /// <param name="param">Parameters</param>
    /// <returns>Instance</returns>
    public static T Instance(params dynamic[] param)
    {
        if (_singleObject == null)
        {
            lock (_lockingObject)
            {
                if (_singleObject == null)
                {
                    _singleObject = (T)Activator.CreateInstance(typeof(T), param);
                }
            }
        }
        return _singleObject;
    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X