Warum brauchen wir einen privaten Konstruktor?

70

Wenn eine Klasse einen privaten Konstruktor hat, kann sie nicht instanziiert werden. Wenn ich also nicht möchte, dass meine Klasse instanziiert wird und sie trotzdem verwendet, kann ich sie statisch machen.

Was nützt ein privater Konstruktor?

Es wird auch in der Singleton-Klasse verwendet, aber gibt es außer dem eine andere Verwendung?

(Hinweis: Der Grund, warum ich den obigen Singleton-Fall ausschließe, ist, dass ich nicht verstehe, warum wir überhaupt einen Singleton benötigen, wenn eine statische Klasse verfügbar ist. Sie können dies aufgrund meiner Verwirrung in der Frage möglicherweise nicht beantworten.)

Rasshme Chawla
quelle

Antworten:

72

Fabrik

Private Konstruktoren können nützlich sein, wenn ein Factory-Muster verwendet wird (mit anderen Worten, eine statische Funktion, mit der eine Instanz der Klasse anstelle einer expliziten Instanziierung abgerufen wird).

public class MyClass
{ 
    private static Dictionary<object, MyClass> cache = 
        new Dictionary<object, MyClass>();

    private MyClass() { }

    public static MyClass GetInstance(object data)
    {
        MyClass output;

        if(!cache.TryGetValue(data, out output)) 
            cache.Add(data, output = new MyClass());

        return output;           
    }
}

Pseudo-versiegelt mit verschachtelten Kindern

Alle verschachtelten Klassen, die von der äußeren Klasse erben, können auf den privaten Konstruktor zugreifen.

Sie können dies beispielsweise verwenden, um eine abstrakte Klasse zu erstellen, von der Sie erben können, aber von niemand anderem (ein internalKonstruktor würde auch hier arbeiten, um die Vererbung auf eine einzelne Assembly zu beschränken, aber der privateKonstruktor erzwingt, dass alle Implementierungen verschachtelte Klassen sind.)

public abstract class BaseClass
{
    private BaseClass() { }

    public class SubClass1 : BaseClass
    {
        public SubClass1() : base() { }
    }

    public class SubClass2 : BaseClass
    {
        public SubClass2() : base() { }
    }
}

Basiskonstruktor

Sie können auch verwendet werden, um "Basis" -Konstruktoren zu erstellen, die von verschiedenen, besser zugänglichen Konstruktoren aufgerufen werden.

public class MyClass
{
    private MyClass(object data1, string data2) { }

    public MyClass(object data1) : this(data1, null) { }

    public MyClass(string data2) : this(null, data2) { }

    public MyClass() : this(null, null) { }
}
Adam Robinson
quelle
Ich mag die Zuweisung in der Cache-Add-Anweisung. Ich habe diese Syntax für träge geladene Eigenschaften mit dem Null-Koaleszenz-Operator verwendet, der mir vorher nicht in den Sinn gekommen ist, dass sie zuvor auch in regulären Methoden verwendet werden kann.
Chris Marisic
1
Das erste Beispiel scheint ein Beispiel für SingletonFactory zu sein?
Ankush Jain
Das Muster des letzten Falls muss nicht sein private, ist aber privategroßartig, da niemand diesen Konstruktor von außen verwenden kann. Ich habe dies verwendet, um für jeden Konstruktor, der in denselben zentralen Code aufgelöst wird, ein etwas anderes Verhalten zu erstellen. (Zum Beispiel :) public MyClass(string data2) : this(null, "Hello " + data2) { }Auch mit der {get;}Eigenschaft von C # 6 ist der Zuweisungscode nur in einem Konstruktorbereich gültig, sodass sie sich tendenziell in diesem privateKonstruktor befinden.
5argon
35

Wie Stefan, Adam und andere hervorgehoben haben, sind private Konstruktoren in Fällen nützlich, in denen es unerwünscht ist, dass eine Klasse durch Code außerhalb der Klasse erstellt wird . Singletons, Fabriken und statische Methodenobjekte sind Beispiele dafür, wo es nützlich ist, Konstruktionen eines Typs einzuschränken, um ein bestimmtes Muster durchzusetzen.

Um auf den zweiten Teil Ihrer Frage zu antworten, warum Singletons benötigt werden, wenn statische Klassen vorhanden sind: Singletons und statische Klassen sind nicht gleichwertig.

Beispielsweise kann eine Singleton-Klasse eine Schnittstelle implementieren, eine statische Klasse nicht. Ein Singleton-Objekt kann als Parameter an Methoden übergeben werden. Dies ist mit statischen Klassen nicht so einfach, ohne auf Wrapper-Objekte oder Reflektion zurückzugreifen. Es gibt auch Fälle, in denen Sie möglicherweise eine Vererbungshierarchie erstellen möchten, in der eine (oder mehrere) der Blattklassen Singleton sind - dies ist auch mit statischen Klassen nicht möglich. Als weiteres Beispiel haben Sie möglicherweise mehrere verschiedene Singletons und möchten möglicherweise eines davon zur Laufzeit basierend auf Umgebungs- oder Konfigurationsparametern instanziieren. Dies ist auch bei statischen Klassen nicht möglich.

Es ist wichtig, die Sprachfunktionen zu verstehen und die richtige für den Job auszuwählen - sie sind aus einem bestimmten Grund da.

LBushkin
quelle
Hervorragende Erklärung für Singleton vs Static Class! Ich lerne daraus! FWIW, Sie können tatsächlich "statische Initialisierung" verwenden, um eine nicht statische Singleton-Klasse zu initialisieren. Siehe die offizielle Dokumentation zu diesem Thema . Das ist ein weiteres Konzept, um Sie am Anfang zu verwirren und am Ende etwas Gutes zu lernen. :-)
RayLuo
15

Manchmal sollte es nicht möglich sein, eine Klasse zu instanziieren. Dies macht dies explizit und erzwingt dies auf Compilerebene.

Singletons sind nur ein Anwendungsfall. Konstantenklassen, statische Methodenklassen und andere Arten von Mustern schreiben vor, dass eine Klasse nicht instanziierbar sein sollte.

Stefan Kendall
quelle
1
Der Vollständigkeit halber: Es ist möglich, eine Klasse als statisch zu markieren, wodurch sichergestellt wird, dass nur statische Elemente zulässig sind und die Klasse nicht instanziiert werden kann.
flq
5

Zweck zum Erstellen des privaten Konstruktors innerhalb einer Klasse

  1. So beschränken Sie die Vererbung einer Klasse

  2. Beschränken Sie die Instanziierung einer Klasse oder das Erstellen mehrerer Instanzen / Objekte.

  3. Um das Singleton-Entwurfsmuster zu erreichen.

    public class TestPrivateConstructor
    {
        private TestPrivateConstructor()
        {  }
    
        public static int sum(int a , int b)
        {
            return a + b;
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            // calling the private constructor using class name directly 
            int result = TestPrivateConstructor.sum(10, 15);
            // TestPrivateConstructor objClass = new TestPrivateConstructor(); // Will throw the error. We cann't create object of this class
        }
    }
    
Kush Kant Dayal Pune
quelle
Danke dafür. Niemand hat darauf hingewiesen, dass dies die Vererbung einer Klasse einschränkt.
Basanta Matia
3

Sie können damit eine Singleton- Instanz erzwingen oder eine Factory- Klasse erstellen .

Eine statische Methode kann den privaten Konstruktor aufrufen, um eine neue Instanz dieser Klasse zu erstellen.

Zum Beispiel eine Singleton-Instanz:

public class Foo
{

  private Foo (){}

  private Foo FooInstance {get;set;}

  public static Foo GetFooInstance ()
  {
    if(FooInstance == null){
      FooInstance = new Foo();
    }

    return FooInstance;
  }

}

Dadurch kann nur eine Instanz der Klasse erstellt werden.

kemiller2002
quelle
2

Wenn Ihr einziges Ziel darin besteht, dass Sie nicht möchten, dass es instanziiert wird, reicht es aus, es statisch zu machen.

Wenn Sie einfach nicht möchten, dass es von außerhalb der Klasse initiiert wird (vielleicht möchten Sie nur, dass Benutzer eine mithilfe einer statischen Factory für die Klasse erhalten), benötigen Sie einen privaten Ctor, um diese öffentlich zugänglichen statischen Daten zuzulassen Fabriken, um es zu instanziieren.

Denken Sie in der Vergangenheit daran, dass es nicht immer möglich war, eine Klasse statisch zu machen ... Wenn Sie den ctor privat machen, war dies eine Möglichkeit, ihn nicht instanziierbar zu machen (ist dies ein Wort?), Bevor das statische Schlüsselwort auf eine Klasse angewendet werden konnte ...

Charles Bretana
quelle
1

In Bezug auf Singletons - Singleton ist ein Entwurfsmuster, das verwendet wird, wenn die Umgebung und die Anforderungen ähnliche Motivationen für die Verwendung des Musters erfüllen. statische Klassen sind eine Sprachfunktion.

Wie in der Antwort von LBushkin erläutert, kann eine bestimmte Implementierung von Singleton den Funktionsumfang statischer Klassen allein überschreiten, obwohl einige der Ziele der Verwendung von Singleton mithilfe statischer Klassen erreicht werden können.

Cade Roux
quelle
0

Wenn die Klasse NUR private Konstruktoren hat, kann sie nicht von außen instanziiert werden.

Sie können auch private und öffentliche Konstruktoren mit unterschiedlichen Signaturen haben.

Cade Roux
quelle
0

Wenn Sie eine Factory für eine Klasse erstellen möchten, können Sie einen privaten Konstruktor verwenden und der Klasse selbst einige statische "Factory" -Methoden hinzufügen, um die Klasse zu erstellen.

Ein Beispiel hierfür ist die Graphics- Klasse mit den From * -Methoden.

GvS
quelle
0

Private Konstruktoren sind Konstruktoren für spezielle Instanzen. und werden in einigen Fällen verwendet, in denen wir eine Klasse erstellen, die nur statische Elemente hat. Daher ist das Erstellen einer Instanz dieser Klasse nutzlos, und hier kommt der private Konstruktor ins Spiel.

Wenn eine Klasse einen oder mehrere private Konstruktoren und keine öffentlichen Konstruktoren hat, können andere Klassen (außer verschachtelte Klassen) keine Instanzen dieser Klasse erstellen.

Beispiel:

class LogClass {

  public static double e = Math.E;  //2.71828

  // Private Constructor:
  private LogClass() { 

 }  
}

Die Deklaration des leeren Konstruktors verhindert die automatische Generierung eines Konstruktors ohne Parameter.

Wenn Sie mit dem Konstruktor keinen Zugriffsmodifikator verwenden, ist dieser standardmäßig weiterhin privat. Lesen Sie mehr: https://qawithexperts.com/tutorial/c-sharp/32/private-constructor-in-c-sharp

user3559462
quelle