Erstellen Sie eine Instanz der abgeleiteten Klasse durch die der Basisklasse ohne hardcoding
Mein problem ist wie folgt:
Ich habe eine base-Klasse muss Abstrakt sein. Es hat mehrere abgeleitete Klassen, jede mit Ihren eigenen besonderen Eigenschaften, die im Eigenschaften-Mitglied.
Ich muss in der Lage sein, erstellen Sie eine neue Instanz einer von dieser abgeleiteten Klassen, also alle Mitglieder sind gleichwertig, aber ändern Sie die neue Instanz nicht ändern, das original.
Endlich, ich will es tun, ohne zu fest in jeder abgeleiteten Typ der Basisklasse. (Das wäre, zugegeben, die einfachste Lösung sein, aber das ist nicht der Punkt)
Alle abgeleiteten Klassen gerecht "ist-ein" - Beziehung zur Basisklasse.
Hier ist der code:
public abstract class BaseClass
{
//Default properties here
int x, y, z, ...;
//Custom made class to hold custom properties
protected Attributes Properties;
public BaseClass createNewInstance()
{
return createNewInstanceStep1();
}
//Each derived class implements their own version of this,
//to handle copying any custom members contained in Properties.
protected abstract BaseClass createNewInstanceStep2();
protected BaseClass createNewInstanceStep1()
{
BaseClass newInstance = new BaseClass(); //<- Doesn't work because class is abstract
//Copy default properties
newInstance.x = x;
newInstance.y = y;
newInstance.z = z;
//Call the new instance's step 2 method, and return the result.
return newInstance.createNewInstanceStep2();
}
}
Das Problem bei diesem code ist die BaseClass newKeyFrame = new BaseClass(); Linie. Als die Klasse ist Abstrakt, Sie kann nicht erstellen Sie eine Instanz von Ihr.
Das problem ist, dass ich in der Lage sein müssen den Konstruktor aufrufen, was den Typ der abgeleiteten Klasse ist, wie Sie alle anderen code in Ihre Konstruktoren, die nicht geteilt werden kann.
Ich habe gehört, dass mit der Spiegelung könnte eine praktikable Lösung, allerdings habe ich keine Ahnung wie.
Wie kann ich dies lösen, ohne fest in einem Fall, für jeden abgeleiteten Typ?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Machen könnte
createNewInstanceStep1
Generika. Ich habe auch geändert, dieStep2
zu gebenvoid
(ich gehe davon aus, dass es zu ändern, die die aktuelle Instanz, also die Rendite wäre immerreturn this;
sowieso), weil es sonst nicht wirklich Sinn macht die Art und Weise, die ich möchte um es hier zu verwenden. Wenn es nicht sinnvoll ist, es zu ändern, wie diese, dann mein ganzer Ansatz nur diese generische Methode will nicht funktionieren.Sowie
createNewInstance
jetzt verwendet reflektion, um zu nennen, das äquivalent vonreturn createNewInstanceStep1<this.GetType()>();
.Wenn dies nicht funktioniert, wird ein weiterer Ansatz ist eine selbst-referenzielle generischen Typ. Es ist gut, um dies zu vermeiden, da es verwirrend ist und insgesamt ein gutes design.
where T : BaseClass, new()
ist zu tun?T
muss einBaseClass
(entwederBaseClass
oder etwas, dass das reicht), und es muss verfügbar, einen parameterlosen Konstruktor. Dies stellt sicher, dass Sie tun könnennew T()
und verwendennewInstance
wie einBaseClass
.Was ist das problem mit der Vermietung der abgeleiteten Klassen müssen die Instanziierung der neuen Instanz?
Können Sie machen createNewInstanceStep1 eine protected void init-Methode, leitet dieses Objekt, und rufen Sie in jede Unterklasse den Konstruktor.
Wie wollen Sie wissen, welche Art von Instanz zu erstellen? Wenn Sie eine vorhandene Instanz der abgeleiteten Klasse und wollen, erstellen einer anderen Instanz, das ist im Grunde identisch ist, sollten Sie Ihre Basis-Typ implementieren Sie eine geschützte virtuelle
CloneBase
Methode, die AnrufeMemberwiseClone
und hat keine tiefen kopieren der base-Typ kennt, und einen öffentlichenClone
Methode, die Ketten zuCloneBase
und casts an der Basis geben. Jedes abgeleitete Typen überschreiben solltenCloneBase
um die Kette zubase.CloneBase
und fügen eventuell notwendige zusätzliche Tiefe zu kopieren (dieser Schritt kann ausgelassen werden, wenn keine zusätzlichen deep-copy Logik erforderlich ist), und auch die Schatten der öffentlichenClone
- Methode mit einem, die Ketten zuCloneBase
auf und CASTET das Ergebnis seiner Art [über einen separatenCloneBase
macht es möglich, beide deklarieren Sie eine neueClone
Methode mit einer anderen Signatur, während auch überschreiben und die Verkettung mit der Basis-Methode der Klasse].Wenn Sie eine vorhandene Instanz von der neuen Klasse, aber wollen, dessen Eigenschaften kopiert werden von einigen anderen Beispiel, könnte eine abstrakte
ConstructInstanceLike(x)
Methode, die jeden abgeleiteten Typ implementieren würden entweder rufen einer Ihrer Konstruktoren, oder Klonen Sie sich selbst und ändern Sie den Klon entsprechen dem übergebenen Objekt. Weder Ansatz ist besonders elegant, aber entweder funktionieren kann.Wenn Sie nicht über eine vorhandene Instanz von der neuen Klasse müssen Sie einige andere Mittel, um etwas von dem entsprechenden Typ. Der schönste Ansatz ist wahrscheinlich zum speichern einer Sammlung von
Func<TParams, TResult>
Delegierten, einer für jeden abgeleiteten Typ von Interesse, und rufen Sie dann eine dieser Funktionen zu erzeugen Sie ein Objekt von einer der zugehörigen abgeleiteten Typ. Es wäre auch möglich zu definieren, eine Schnittstelleaber in vielen Fällen eine Stellvertretung wird bequemer sein, mit zu arbeiten.
AddFactory<FooBar>((x) => new FooBar(x));
). Ist das zu viel "hard coding" für Ihren Geschmack?CopyFrom
- Methode auf die Instanz (was könnte es Erben von der Basisklasse) zu kopieren Ihrer Mitglieder. Ein Ansatz, derMemberwiseClone
könnten, zu vermeiden die Notwendigkeit für einenew
Einschränkung, obwohl, müsste man vorsichtig sein, um die Gültigkeit der Daten in dem geklonten Objekt die sollte nicht vorhanden sein, in die neue Instanz.