2013-05-19 18 views
26

Czy jest jakaś różnica między A i B?Jaka jest różnica między klasą z prywatnym konstruktorem a klasą szczelną mającą prywatny konstruktor?

Klasa A ma prywatny konstruktor:

class A 
{ 
    private A() 
    { } 
} 

klasy B jest szczelnie zamknięty i posiada prywatny konstruktor:

sealed class B 
{ 
    private B() 
    { } 
} 
+0

Dlaczego chciałbyś mieć zajęcia z prywatnym konstruktorem? –

+5

@MarkusMeskanen Klasa może mieć publiczną metodę statycznej fabryki, która musi być jedynym sposobem, w jaki klient może utworzyć wystąpienie klasy. –

+3

@MarkusMeskanen [Singletons] (http://msdn.microsoft.com/en-us/library/ff650316.aspx) –

Odpowiedz

39

Tak A może być dziedziczony przez klasę zagnieżdżoną, podczas gdy B nie może być w ogóle dziedziczony. Jest to całkowicie legalne:

public class A { 
    private A() { } 

    public class Derived : A { } 
} 

Należy pamiętać, że każdy kod może utworzyć new A.Derived() lub dziedziczyć A.Derived (jego konstruktor jest publiczny), ale nie ma innych zajęć poza tekstem źródłowym A może dziedziczyć bezpośrednio z A.

Typowym zastosowaniem czegoś takiego to klasa z wartościami enum-like, ale które mogą mieć niestandardowe zachowanie:

public abstract class A { 
    private A() { } 

    public abstract void DoSomething(); 

    private class OneImpl : A { 
    public override void DoSomething() { Console.WriteLine("One"); } 
    } 

    private class TwoImpl : A { 
    public override void DoSomething() { Console.WriteLine("Two"); } 
    } 

    public static readonly A One = new OneImpl(); 
    public static readonly A Two = new TwoImpl(); 
} 
+0

Chętnie oferuję mój +1 tutaj :-) – Jon

+0

Haha! Teraz to * nie * jest wymyślone, ponieważ tak naprawdę możesz chcieć to zrobić (choć nie jest to powszechne).+1 :) :) –

+2

Zasadniczo jest to to samo, co zapewnienie innych konstruktorów na A, z wyjątkiem tego, że są to super "fantazyjne" konstruktory oparte na klasach zagnieżdżonych. –

5

oparta na drugim artykule, jeżeli jest to tylko konstruktor nie będzie mógł aby utworzyć instancję klasy A lub klasy B. Ponieważ klasa A ma prywatnego konstruktora, nie można jej uzyskać z powodu jej poziomu ochrony, ani też nie można uzyskać z B z zapieczętowaniem.

Inheritance (C# Programming Guide)

Pochodzące Klasa Dostęp do Base Class Członkowie klasy pochodnej ma dostęp dla publiczności, chronionym, wewnętrznego i wewnętrznych chronionych członków klasy bazowej. Mimo że klasa pochodna dziedziczy prywatne klasy klasy bazowej, nie może uzyskać dostępu do tych elementów. Jednak wszyscy ci prywatni członkowie są nadal obecni w klasie pochodnej i mogą wykonywać tę samą pracę, którą wykonaliby w samej klasie bazowej. Na przykład załóżmy, że zabezpieczona metoda klasy bazowej uzyskuje dostęp do pola prywatnego. To pole musi być obecne w klasie pochodnej dla odziedziczonej metody klasy podstawowej , aby działała poprawnie.

Private Constructors (C# Programming Guide)

prywatny konstruktor jest specjalny konstruktor instancji. Jest to powszechnie używane w klasach zawierających tylko statyczne elementy. Jeśli klasa ma jeden lub więcej prywatnych konstruktorów i nie ma publicznych konstruktorów, wówczas inne klasy (z wyjątkiem klas zagnieżdżonych) nie mogą tworzyć instancji tej klasy w postaci .

+0

Nieco pedantycznie, mógłbym stworzyć dowolną liczbę wystąpień A lub B, gdyby mieli metody fabryczne, nawet jeśli nie mieli konstruktorów innych niż wyszczególnieni. –

+0

Nie można wyprowadzić ani A ani B. Nie można der-A z powodu prywatnego konstruktora. Pytanie może być następujące: Jeśli istnieje klasa z prywatnym konstruktorem, istnieje jakakolwiek różnica, jeśli zaznaczysz ją jako zapieczętowaną. – jannagy02

+0

@ jannagy02: Aktualizowałem to podczas pisania Twojego komentarza :-) – Harrison

1

Można utworzyć instancję klasy sealed, ale klasa z prywatnym konstruktorem nie może. Oboje nie dopuszczają dziedziczenia, ale nie jest to celem prywatnego konstruktora.

Powodem użycia prywatnego konstruktora jest zatrzymanie tworzenia instancji. Jest to często używane w statycznych metodach fabrycznych, gdzie musisz wywołać MyClass::Create(...), aby utworzyć instancję.

Nie ma to nic wspólnego z uszczelnieniem, które zatrzymuje dziedziczenie. Jeśli używasz prywatnego konstruktora do zatrzymania dziedziczenia, używasz niewłaściwego podejścia. Istnieją sposoby na obejście prywatnego konstruktora w celu dziedziczenia.

4

Istnieje jedna niewielka różnica, jaką można uzyskać dzięki analizie kodu.

Rozważmy następujący kod:

public class Base 
{ 
    public virtual void Function() 
    { 
    } 
} 

public class Derived: Base 
{ 
    public static Derived Create() 
    { 
     return new Derived(); 
    } 

    private Derived() 
    { 
     // Code analysis warning: CS2214 "Do not call overridable methods in constructors". 
     Function(); 
    } 
} 

Jest Analiza kod ostrzegawczy dla pochodnych konstruktora, ponieważ mamy dostęp metodę wirtualną z nim, co jest złe.

Jeśli jednak zrobić Derived uszczelniony, ostrzeżenie Code Analysis odchodzi.

Jest więc mała i różna dla Ciebie wymyślona. ;)

0

Jeśli klasa jest uszczelniony, nie będzie możliwe zdefiniowanie klasy wynikającemu z tego. Klasa z prywatnym konstruktorem może być utworzona przez metody fabryczne w klasie, ani dziedziczona przez klasy zagnieżdżone (które, w zależności od poziomu dostępu i konstruktorów, mogą być dziedziczone przez zewnętrzny kod). Dodatkowo, dowolny kod zewnętrzny może zadeklarować klasy, które pochodzą od niego i spełniają ograniczenie new(). Jeśli klasa pochodna nie może wywołać konstruktora bazowego, jej własne konstruktory nie będą miały innego wyjścia, jak tylko wyrzucić wyjątek, awarię lub zawiesić się, ale takie zachowanie nie będzie wykrywalne, dopóki nie zostanie podjęta próba zbudowania instancji; kod skompilowałby się dobrze.

0
public class Test 
{ 


    private Test() 
    { 
     Debug.WriteLine("private constructor has been called in class Test"); 
    } 

    public virtual string Run() 
    { 
     return "Test.Run"; 
    } 

    public static Test GetTestRequest() 
    { 
     return new Test(); 
    } 

    public static DerivedTest GetDerivedTestRequest() 
    { 
     return new DerivedTest(); 
    } 

    public class DerivedTest:Test 
    { 
     public DerivedTest() 
     { 
      Debug.WriteLine("public constructor has been called in derived class DerivedTest."); 
     } 

     public override string Run() 
     { 
      return "DerivedTest.Run"; 
     } 
    } 
} 

Debug.WriteLine (Test.GetTestRequest(). Run()); Debug.WriteLine (Test.GetDerivedTestRequest(). Uruchom());

============================================== ============== wyjściowa:

prywatny konstruktor został powołany w klasie testu Test.Run

prywatny konstruktor został powołany w klasie testu konstruktor publiczny został wywoływana w klasie pochodnej DerivedTest. DerivedTest.Run

Tak więc klasa zagnieżdżona może pochodzić z zewnętrznej klasy bazowej mającej jedyny prywatny konstruktor.