Frage

Stellen eine Basisklasse mit vielen Konstrukteuren und eine virtuelle Methode

public class Foo
{
   ...
   public Foo() {...}
   public Foo(int i) {...}
   ...
   public virtual void SomethingElse() {...}
   ...
}

und jetzt will ich eine abgeleitete Klasse erstellen, die die virtuelle Methode überschreibt:

public class Bar : Foo 
{
   public override void SomethingElse() {...}
}

Und noch ein Nachkomme, die etwas mehr Sachen tut:

public class Bah : Bar
{
   public void DoMoreStuff() {...}
}

Muss ich wirklich alle Konstrukteure von Foo in Bar und Bah kopieren? Und dann, wenn ich eine Konstruktor Unterschrift in Foo ändern, habe ich zu aktualisieren, um es in Bar und Bah?

Gibt es keine Möglichkeit Konstrukteuren zu erben? Gibt es keine Möglichkeit, die Wiederverwendung von Code zu fördern?

War es hilfreich?

Lösung

Ja, sehen Sie die Konstrukteure implementieren, den Sinn für jede Ableitung zu machen und dann das base Schlüsselwort verwenden, dass Konstruktor an der entsprechenden Basisklasse oder das this Schlüsselwort zu leiten einen Konstruktor an einem anderen Konstruktor in der gleichen Klasse zu lenken.

Wenn der Compiler Annahmen über Vererbungs Konstrukteuren gemacht, würden wir nicht in der Lage, richtig zu bestimmen, wie unsere Objekte instanziiert wurden. In den meisten Fällen sollten Sie darüber nachdenken, warum Sie so viele Konstrukteure haben und betrachten sie nur ein oder zwei in der Basisklasse zu reduzieren. Die abgeleiteten Klassen können dann einige von ihnen mit konstanten Werten wie null maskieren und nur die notwendig diejenigen durch ihre Konstrukteure aus.

Update

In C # 4 Sie Standard-Parameterwerte angeben können und benannte Parameter verwenden einen einzigen Konstruktor Abstützkonfigurationen mehrere Argument zu machen, anstatt je nach Konfiguration einen Konstruktor haben.

Andere Tipps

387 Konstrukteuren ?? Das ist Ihr Hauptproblem. Wie wäre es damit statt?

public Foo(params int[] list) {...}

Ja, müssen Sie alle 387 Konstrukteuren kopieren. Sie können einige Wiederverwendung tun, indem sie umleiten:

  public Bar(int i): base(i) {}
  public Bar(int i, int j) : base(i, j) {}

, aber das ist das Beste, was Sie tun können.

Schade, dass wir sind irgendwie gezwungen, den Compiler zu sagen, die offensichtlich:

Subclass(): base() {}
Subclass(int x): base(x) {}
Subclass(int x,y): base(x,y) {}

Ich brauche nur 3 Konstrukteure in 12 Unterklassen zu tun, so ist es keine große Sache, aber ich bin nicht allzu gern, dass auf jeder Unterklasse zu wiederholen, nachdem sie verwendet wird, um es nicht lange, so zu schreiben. Ich bin sicher, es gibt einen triftigen Grund dafür, aber ich glaube nicht, dass ich jemals ein Problem festgestellt, dass diese Art von Einschränkung erfordert.

Vergessen Sie nicht, dass Sie auch Konstrukteure auf andere Konstrukteure auf dem gleichen Niveau der Vererbung umleiten kann:

public Bar(int i, int j) : this(i) { ... }
                            ^^^^^

Eine weitere einfache Lösung könnte sein, eine Struktur oder einfache Datenklasse zu verwenden, um die Parameter als Eigenschaften enthält; Auf diese Weise können alle Standardwerte und Verhaltensweisen einrichten vor der Zeit haben kann, vorbei an der „Parameter-Klasse“ in als einziger Konstruktorparameter:

public class FooParams
{
    public int Size...
    protected myCustomStruct _ReasonForLife ...
}
public class Foo
{
    private FooParams _myParams;
    public Foo(FooParams myParams)
    {
          _myParams = myParams;
    }
}

Dies vermeidet das Durcheinander von mehreren Konstrukteuren (manchmal) und gibt starke Typisierung, Standardwerte und andere Leistungen, die nicht von einem Parameter-Array zur Verfügung gestellt. Es macht es auch leicht nach vorne zu tragen, da alles, was von Foo erbt noch bekommen, oder sogar, FooParams nach Bedarf hinzufügen. Sie müssen noch den Konstruktor kopieren, aber Sie immer (die meiste Zeit) nur (in der Regel) immer (zumindest vorerst) benötigt einen Konstruktor.

public class Bar : Foo
{
    public Bar(FooParams myParams) : base(myParams) {}
}

Ich mag das überladene Initailize () und Class Factory-Muster nähert sich besser, aber manchmal braucht man nur einen Smart-Konstruktor hat. Nur so ein Gedanke.

Wie Foo ist eine Klasse, können Sie nicht virtuell überlastet Initialise() Methoden erstellen? Dann würden sie auf Unterklassen zur Verfügung stehen und noch erweiterbar?

public class Foo
{
   ...
   public Foo() {...}

   public virtual void Initialise(int i) {...}
   public virtual void Initialise(int i, int i) {...}
   public virtual void Initialise(int i, int i, int i) {...}
   ... 
   public virtual void Initialise(int i, int i, ..., int i) {...}

   ...

   public virtual void SomethingElse() {...}
   ...
}

Dies sollte nicht eine höhere Leistungskosten haben, wenn Sie eine Menge Standardeigenschaftswerte haben und Sie treffen es eine ganze Menge.

public class BaseClass
{
    public BaseClass(params int[] parameters)
    {

    }   
}

public class ChildClass : BaseClass
{
    public ChildClass(params int[] parameters)
        : base(parameters)
    {

    }
}

Ich persönlich denke, das ist ein Fehler auf Microsofts Teil, sollten sie der Programmierer Sichtbarkeit von Konstruktoren, Methoden und Eigenschaften in Basisklassen erlaubt haben, außer Kraft zu setzen, und dann zu machen, so dass Konstrukteure immer vererbt.

So können wir einfach nur außer Kraft setzen (mit geringerer Sichtbarkeit -. Dh Private) die Konstrukteure wir wollen DONT stattdessen alle Konstrukteure hinzufügen zu haben wir wollen. Delphi macht es auf diese Weise, und ich vermisse es.

Nehmen Sie zum Beispiel, wenn Sie die System.IO.StreamWriter Klasse außer Kraft setzen möchten, müssen Sie alle 7 Konstrukteure auf Ihre neue Klasse hinzuzufügen, und wenn Sie kommentieren möchten müssen Sie jeweils mit dem Header XML kommentieren. Um es noch schlimmer, dosnt die Metadaten-Ansicht der XML-Kommentare als richtige XML-Kommentare setzen, also müssen wir gehen Zeile für Zeile und kopieren und einfügen. Was hat Microsoft denke hier?

Ich habe ein kleines Programm tatsächlich geschrieben, in dem Sie in den Metadaten-Code einfügen können, und es wird sie in XML-Kommentare konvertieren Sichtbarkeit mit außer Kraft gesetzt.

  

Muss ich wirklich alle Konstrukteure von Foo in Bar und Bah kopieren? Und dann, wenn ich einen Konstruktor Unterschrift in Foo ändern, habe ich zu aktualisieren, um es in Bar und Bah?

Ja, wenn Sie verwenden Konstrukteurs-Instanzen zu erstellen.

  

Gibt es keine Möglichkeit Konstrukteuren zu erben?

Nein.

  

Gibt es keine Möglichkeit, die Wiederverwendung von Code zu fördern?

Nun, ich werde nicht in bekommen, ob Konstrukteurs erben eine gute oder eine schlechte Sache sein würde und ob es wäre die Wiederverwendung von Code zu fördern, da wir sie nicht und wir nicht, sie in Gang zu bringen. : -)

Aber hier im Jahr 2014, mit der aktuellen C #, können Sie etwas sehr viel erhalten wie Konstrukteurs geerbt durch eine generische create Methode anstelle verwenden. Es kann ein nützliches Werkzeug sein in Ihrem Gürtel haben, aber man würde es nicht leicht zu erreichen. Ich erreichte vor kurzem für sie, wenn sie mit zu müssen passieren, etwas in den Konstruktor einer Basistyp verwendet in ein paar hundert abgeleiteten Klassen (bis vor kurzem konfrontiert, hat die Basis keine Argumente benötigen, und so der Standardkonstruktor war in Ordnung - das abgeleitete Klassen erklären nicht an allen Konstrukteuren, und bekam die automatisch mitgelieferten).

Es sieht wie folgt aus:

// In Foo:
public T create<T>(int i) where: where T : Foo, new() {
    T obj = new T();
    // Do whatever you would do with `i` in `Foo(i)` here, for instance,
    // if you save it as a data member;  `obj.dataMember = i;`
    return obj;
}

Das ist, sagt, dass Sie die generische create Funktion aufrufen kann einen Typparameter verwendet, die jeder Subtyp von Foo ist, die eine Null-Argumente Konstruktor hat.

Dann wird anstelle Bar b new Bar(42) tun, würden Sie dies tun:

var b = Foo.create<Bar>(42);
// or
Bar b = Foo.create<Bar>(42);
// or
var b = Bar.create<Bar>(42); // But you still need the <Bar> bit
// or
Bar b = Bar.create<Bar>(42);

Es habe ich die create Methode gezeigt direkt auf Foo zu sein, aber natürlich könnte es in einer Fabrik Klasse von einer Art sein, wenn die Informationen, es können ist die Einrichtung von dieser Factory-Klasse eingestellt werden.

Nur für Klarheit: Der Name create nicht wichtig ist, könnte es makeThingy oder was auch immer Sie mögen werden

.

Voll Beispiel

using System.IO;
using System;

class Program
{
    static void Main()
    {
        Bar b1 = Foo.create<Bar>(42);
        b1.ShowDataMember("b1");

        Bar b2 = Bar.create<Bar>(43); // Just to show `Foo.create` vs. `Bar.create` doesn't matter
        b2.ShowDataMember("b2");
    }

    class Foo
    {
        public int DataMember { get; private set; }

        public static T create<T>(int i) where T: Foo, new()
        {
            T obj = new T();
            obj.DataMember = i;
            return obj;
        }
    }

    class Bar : Foo
    {
        public void ShowDataMember(string prefix)
        {
            Console.WriteLine(prefix + ".DataMember = " + this.DataMember);
        }
    }
}

Das Problem ist nicht, dass Bar und Bah haben 387 Konstrukteuren zu kopieren, das Problem ist, dass Foo 387 Konstrukteuren hat. Foo deutlich machen zu viele Dinge - Refactoring schnell! Auch wenn Sie einen wirklich guten Grund haben Werte im Konstruktor festgelegt (die, wenn Sie einen parameterlosen Konstruktor zur Verfügung stellen, werden Sie wahrscheinlich nicht), würde ich mit Eigenschaft bekommen / Einstellung empfehlen.

Nein, Sie müssen nicht alle 387 Konstrukteuren kopieren Bar und Bah. Bar und Bah können so viele oder so wenige Konstrukteure haben, wie Sie unabhängig von möchten, wie viele Sie definieren auf Foo. Zum Beispiel könnten Sie wählen, nur eine Bar Konstruktor zu haben, die Foo mit Foo 212. Konstruktor konstruiert.

Ja, alle Konstrukteure Sie in Foo ändern, dass Bar oder Bah davon abhängen, benötigen Sie Bar und Bah ändern sich entsprechend.

Nein, es gibt keine Möglichkeit, in .NET Konstrukteuren zu erben. Aber man kann durch den Aufruf einer Basisklasse Konstruktor innerhalb der Unterklasse Konstruktor der Wiederverwendung von Code erreichen oder durch eine virtuelle Methode aufrufen Sie definieren (wie Initialize ()).

Sie können möglicherweise eine Version der C ++ virtuelles Konstruktor Idiom . Soweit ich weiß, ist C # nicht kovarianten Rückgabetypen unterstützen. Ich glaube, das ist bei vielen Völkern der Wunschliste.

Zu viele Konstrukteure ist ein Zeichen eines gebrochenen Design. Besser eine Klasse mit wenigen Konstrukteuren und die Fähigkeit, Eigenschaften einzustellen. Wenn Sie wirklich die Kontrolle über die Eigenschaften benötigen, eine Fabrik im gleichen Namensraum betrachten und die Eigenschaft Setter interne machen. Lassen Sie die Fabrik entscheiden, wie die Klasse zu instanziiert und seine Eigenschaften festgelegt. Die Fabrik kann Methoden, die so viele Parameter wie nötig, um die Aufgabe richtig zu konfigurieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top