Laden...

[erledigt] Ist "virtual" zu "override" zu ändern ein Breaking-Change? [==> Ja]

Erstellt von JuyJuka vor 11 Jahren Letzter Beitrag vor 11 Jahren 3.879 Views
JuyJuka Themenstarter:in
2.187 Beiträge seit 2005
vor 11 Jahren
[erledigt] Ist "virtual" zu "override" zu ändern ein Breaking-Change? [==> Ja]

Hallo @All,

hoffentlich habe ich ein solche Thema nicht mit/in der Suchfunktion übersehen.

Ich habe ein Property* in einer Klasse und in einer davon erbenden Klasse mit dem gleichen Namen* deklariert, was ja nur eine Warnung im Compiler verursacht. Die Assembly mit diesen beiden Typen ist raus und in verwendung. Wenn ich jetzt diese Warnung beheben will müsste ich das virtual des Properties in der erbenden Klasse in ein override ändern.
Wäre das ein Bracking-Change? Und wenn ja warum? Und was würde das hinzufügen von new vor das virtual verursachen?

Gruß
Juy Juka

* es könnte genauso gut eine Methode sein, dann müsste halt Name und Signatur übereinstimmen.

S
417 Beiträge seit 2008
vor 11 Jahren

Hallo,

klar hast du dann eine Veränderung im Laufzeitverhalten, was ja ganz einfach an einem Beispiel zu beweisen ist:

class Program
{
	static void Main(string[] args)
	{
		A x = new B();
		x.DoIt();
	}
}

public class A
{
	public void DoIt()
	{
		Console.WriteLine("A");
	}
}

public class B : A
{
	public void DoIt()
	{
		Console.WriteLine("B");
	}
}

Das ist dein momentaner Stand, welcher hier die DoIt()-Methode von Klasse A aufrufen würde. Nach deiner Änderung mittels override wird die DoIt()-Methode von B aufgerufen.

U
1.688 Beiträge seit 2007
vor 11 Jahren

Und was würde das hinzufügen von :::

Genau das sollte aber die "richtige" Behebung der Warnung sein: diese sagt ja gerade, dass die neue Property/Methode die alte ausblendet und man "new" verwenden soll, wenn das beabsichtigt ist. Auch das "virtual" ändert daran nichts.

Edit: "override" lässt ja schon der Compiler nicht zu.

C
258 Beiträge seit 2011
vor 11 Jahren

virtual ist ja für die Basisklasse und nicht für die Subklasse.

deine Warnung entsteht nur deswegen weil es meist nicht so beabsichtigt ist, und wenn es doch so gewollt ist das ein Objekt der Subklasse nur dann ihr Methode ausführt wenn auch die Referenz auf die Subklasse zeigt (was zu 95% eben nicht gewollt ist) kann man mit dem Schlüsselwort new in der Subklasse sagen das diese Funktionalität gewollt ist.

Virtual in der Basisklasse und Override in der Subklasse verändert wie schon gesagt die Funktionalität.

Hinweis von herbivore vor 11 Jahren

... wenn auch die Referenz auf die Subklasse zeigt ...

es müsste heißen:

... wenn die Variable, die die Referenz enthält, vom Typ der Subklasse ist ...

Und das ist ja das verrückte und im objektorientierten Sinne unpassende an new, dass die aufgerufene Methode dann vom Typ der Variable und nicht vom Typ des Objekt abhängt.

JuyJuka Themenstarter:in
2.187 Beiträge seit 2005
vor 11 Jahren

Hallo Sarc, Hallo ujr, Hallo Console32,

danke für eure Posts.

Dank Sarc ist jetzt klar, dass es ein BreakingChange ist und ich werde es nicht ändern.
new werde ich einfügen, da es die Warnung "behebt" aber eh keine Auswirkung auf den Programmablauf/die Auflösung der Member hat, danke ujr.
Tja, Console32, hat recht, dieses Verhalten war sowieso keine Absicht und wurde leider übersehen. Da es aber trotzdem Funktioniert und ich im Notfall auch an das Property der Basis-Klasse komme, kann ich es so belassen.

Gruß
Juy Juka

49.485 Beiträge seit 2005
vor 11 Jahren

Hallo JuyJuka,

ob es möglich ist, in der Unterklasse virtual durch override zu ersetzen, hängt davon ab, ob die Methode bereits in der Oberklasse virtual ist. Es geht nur, wenn sie es ist. Dann ist Verwendung von override aber nicht nur die - im objektorientierten Sinne - einzig korrekte Lösung, sondern es wäre unpassend von einem Breaking Change zu sprechen*. Denn dann hat der Programmierer der Oberklasse ja explizit erlaubt, dass Unterklassen das Verhalten dieser Methode ändern dürfen.

Wenn das virtual dagegen der Oberklasse fehlt, ist an sich schon Hopfen und Malz für eine im objektorientierten Sinne korrekte Lösung verloren. Anderseits ist es in diesem Fall gar nicht möglich einen Breaking Change herbeizuführen, weil die neue Methode nur dann aufgerufen wird, wenn der statische Typ der Variable vom Typ der Unterklasse ist. Das kann bei einer neu hinzugefügten Unterklasse aber nur in neuem Code und nicht in bestehendem Code der Fall sein. Selbst bei einer bestehenden Klasse bekommt mangels Alternative keinen Breaking Change, denn override scheidet wie gesagt aus und ob new oder nicht ändert nichts an der Semantik, sondern beeinflusst nur, ob die Warnung erscheint oder nicht. Das virtual in der Unterklasse macht erst für deren Unterklassen einen semantischen Unterschied, nicht aber für sie selbst und nicht für ihre Oberklasse.

Im Ergebnis liegt also weder in dem einen noch in dem anderen Fall ein Breaking Change vor.

herbivore

* Gemeint ist, dass es kein Breaking Change darstellt, wenn man eine Unterklasse schreibt, die override benutzt. Wie ich in meiner Antwort weiter unten aber anerkenne, wäre die nachträgliche Änderung von virtual in override insofern ein Breaking Change, als dass es Fälle geben kann, in denen eine andere Methode aufgerufen werden würde als vor der Änderung.

PS: Warum bei new Hopfen und Malz verloren? Wie ich schon oben (im Modhinweis) schrieb:

Und das ist ja das verrückte und im objektorientierten Sinne unpassende an new, dass die aufgerufene Methode dann vom Typ der Variable und nicht vom Typ des Objekt abhängt.

PSS:

Fehlermeldung im Fall 1 (Oberklassen-Methode virtual):

Fehlermeldung:
warning CS0114: "B.DoIt()" blendet den vererbten Member "A.DoIt()" aus. Damit der aktuelle Member diese Implementierung überschreibt, fügen Sie das override-Schlüsselwort hinzu. Ansonsten fügen Sie das new-Schlüsselwort hinzu.

Fehlermeldung im Fall 2 (Oberklassen-Methode nicht virtual):

Fehlermeldung:
warning CS0108: "B.DoIt()" blendet den vererbten Member "A.DoIt()" aus. Verwenden Sie das new-Schlüsselwort, wenn das Ausblenden vorgesehen war.

JuyJuka Themenstarter:in
2.187 Beiträge seit 2005
vor 11 Jahren

Hallo herbivore,

stimmt, wenn die Unterklasse neu ist, ist es kein BreakingChange, weil die Unterklasse ja noch nicht verwendet wird.

In meinem Fall ist es aber ein BreackingChange da die Unterklasse nicht neu ist, sondern die Warning durch das vergessene new/override nicht aufgefallen war. Es wird die Klasse also schon sehr oft verwendet und auch als Konkreter Typ.

Und gefühlt ist es das auch in den überwiegenden Fällen ein BreackingChange, da man ja nicht weiß wo/wer auf das Property/die Klasse zugreift so bald man es einmal Veröffentlicht hat und sich (wie Sarc gezeigt hat) das Verhalten ändert.

Gruß
Juy Juka

49.485 Beiträge seit 2005
vor 11 Jahren

Hallo JuyJuka,

wie du mir auf Nachfrage mitgeteilt hast, ist die Methode/Property sowohl in der Oberklasse als auch in der Unterklasse als virtual gekennzeichnet.

Das ist zwar nicht sinnvoll und auch nicht objektorientiert 😃 aber dann macht eine nachträgliche Änderung in der Unterklasse von virtual in override in der Tat einen semantischen Unterschied. Das virtual in der Unterklasse unterbricht die ansonsten nahtlose Kette dynamischer Bindung und definiert eine neue Methode, die mit der Methode in der Oberklasse nichts gemein hat (außer dem gleichen Namen und den gleichen Parametern). Wenn man new davor schreibt, erkennt man diesen _a_normalen Zustand an. Ein override würde hingehen die Kette weiderherstellen und die Methode wäre dann eine echte Überschreibung der Methode aus der Oberklasse. Es könnte dann Stellen im bestehenden Code geben, an deren nach der Änderung die Methode aus B aufgerufen wird, wo bisher die Methode aus A aufgerufen wurde.

In dem Falle wäre also einen Breaking Change nicht auszuschließen. Ob er tatsächlich eintritt, hängt davon ab, ob es Fälle gibt, in denen x.DoIt() aufgerufen wird, wobei x vom Typ A, aber das enthaltene Objekt vom Typ B ist.

herbivore