2010-10-06 14 views
18

Wiem, że nie jest możliwe dziedziczenie konstruktorów w języku C#, ale prawdopodobnie istnieje sposób, aby zrobić to, co chcę zrobić.C#: dziedziczenie konstruktorów

Posiadam klasę podstawową, która jest dziedziczona przez wiele innych klas, i ma metodę Init, która wykonuje kilka inicjalizacji przyjmujących 1 parametr. Wszystkie inne klasy dziedziczące również potrzebują tego inicjalizacji ale będę musiał utworzyć osobne konstruktorów dla nich wszystkich, którzy chcieliby w ten sposób:

public Constructor(Parameter p) { 
    base.Init(p); 
} 

To całkowicie narusza suchej zasady! Jak mogę zainicjować wszystkie potrzebne rzeczy bez tworzenia kilkudziesięciu konstruktorów?

+2

Gorsze niż naruszanie zasad DRY stanowi naruszenie zasady niezmienności. "Init" jako nazwa metody jest generalnie silnym znakiem, że obiekty są niepotrzebnie obecne w nieważnych stanach, w których jedyną rzeczą, na której są one dobre, jest powodowanie błędów. –

+1

C# in wcale nie podąża za DRY. Może to być uciążliwe, ale ... szczerze mówiąc, nie możesz mi powiedzieć, że nie jesteś zmęczony pisaniem "publicznych", "chronionych" i "prywatnych" w kółko i na okrągło? –

+1

@ SlippD.Thompson: To kolejny obszar, w którym C++ jest faktycznie * mniej * bardziej rozwlekły niż łatwiejsze języki ... Poprzedni, który właśnie widziałem, dotyczył eksponowania konstruktorów bazowych w klasie pochodnej. –

Odpowiedz

47

Nie trzeba tworzyć wielu konstruktorów, wszystkie z tym samym kodem; tworzysz tylko jeden, ale klasy pochodne wywołają konstruktor podstawowy:

public class Base 
{ 
    public Base(Parameter p) 
    { 
     Init(p) 
    } 

    Init(Parameter p) 
    { 
     // common initialisation code 
    } 
} 

public class Derived : Base 
{ 
    public Derived(Parameter p) : base(p) 
    { 

    } 
} 
+1

Tego właśnie potrzebuję. Chociaż będę musiał tworzyć konstruktory dla klas, które ich nie mają, nie będę musiał powtarzać kodu. – Alex

+1

dlaczego głosowanie w dół? –

+1

Żałuję, że C# nie ma czegoś takiego jak dziedziczące konstruktory C++, nadal denerwujące jest wywoływanie wszystkich konstruktorów bazowych. –

7

zmienić funkcję init jest to konstruktor klasy bazowej, a następnie wywołać ją z odziedziczonych obiektów tak:

public InheritedObject(Parameter p) : base(p) 
{ 
} 

Konstruktor baza zostanie wywołany przed jakiegokolwiek kodu w konstruktorze sama biegnie .

2

Coś takiego?

public Constructor(Parameter p) : base(p) { 

} 

I klasa bazowa:

public Base(Parameter p) 
{ 
    Init(p); 
} 

Można nawet zaznaczyć metodę Init jako wirtualny, dzięki czemu można zrobić kilka słodkich nadpisanie w swoich innych zajęć, jeśli będzie trzeba! ;)

public virtual void Init() { } 

iw waszych innych klasach:

public override void Init() { base.Init(); //Do other stuff } 
+2

Mimo że musisz bardzo ostrożnie wywoływać wirtualną metodę z konstruktora - konstruktor podklasy nie uruchomi się, gdy nadpisana zostanie wywołana metoda przez nadklasę, więc zmienne członkowskie itp. nie zostałyby zainicjowane. – thecoop

+0

prawda :) ale znajdziesz ten problem naprawdę szybko .. – Arcturus

+1

Metoda wirtualnego init wydaje się jednak bezcelowa. Normalnie powinieneś unikać pracy w konstruktorach i używać ich tylko do inicjowania, a jeśli jest to tylko inicjowanie, to dlaczego nie skorzystać z konstruktora? – AHM

5

Jedynym sposobem, aby nie powtórzyć wezwanie base.Init jest zamiast wywołać konstruktora bazowy

class Base 
{ 
    public Base(Parameter p) 
    { 
    this.Init(p) 
    } 

    private void Init(Parameter p) 
    { 
     ... 
    } 
} 

class Inherited : Base 
{ 
    public Inherited(Parameter p) 
    : base(p) 
    { 
     // other constructor logic, but Init is already called. 
    } 
} 
3

Nie można dziedziczyć konstruktorów, ale możesz wywoływać je z konstruktorów pochodnych dla dzieci. Jeśli uczynisz klasy bazowe domyślnym konstruktorem prywatnym, wymusisz wybór konstruktora bazowego za każdym razem, gdy utworzysz klasę pochodną.