Laden...

Einsatz protected & virtual (statt private & non-virtual)

Erstellt von Desert Fox vor 13 Jahren Letzter Beitrag vor 13 Jahren 5.521 Views
D
Desert Fox Themenstarter:in
33 Beiträge seit 2010
vor 13 Jahren
Einsatz protected & virtual (statt private & non-virtual)

Ich bin ja jemand der der meinung ist das man den programmierer nicht einschränken sollte was er tun kann und was nicht und finde man sollte eigentlich fast alles protected und virtual markieren. Andererseits, wer überschreibt schon mal was in einer Firmenapi oder einem bestehenden Programm? Wenn dann gibt es doch einen Featurerequest der API oder?

Wie steht ihr dazu, was markiert ihr als protected/virtual bzw markiert ihr garnichts als protected oder virtual?

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

das lässt sich nicht pauschal beantworten denn es kommt auf den konkreten Fall an.
Von daher halte ich solche Pauschalfragen für überhaupt nicht sinnvoll. Welche (sinnvolle) Antwort oder Erkenntnis erwartest du dir davon?

protected dann wenn in einer abgeleiteten Klasse auch auf "private" Member der Basisklasse zugegriffen werden soll.

virtual halt dann wenn etwas überschreibbar sein soll 😉

Du kannst dir dazu auch durchlesen was Anders Hejlsberg dazu zu sagen hat. Siehe Versioning, Virtual, and Override - A Conversation with Anders Hejlsberg, Part IV

wer überschreibt schon mal was in einer Firmenapi oder einem bestehenden Programm?

Ich. Nur zB für eine Strategie und dazu ist beim Überschreiben kein separater Feature-Request notwendig denn die Entscheidung zur Wahl der Strategie ist durch einen solchen Request schon abgeckt.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

D
Desert Fox Themenstarter:in
33 Beiträge seit 2010
vor 13 Jahren

mir ging es darum wonach ihr entscheidet wann ihr etwas also protected/virtual markiert,
z.B. wenn es eventuell einmal sein könnte das irgentwann jemand da mal überschreiben können wollte und desshalb markier mans doch lieber als virtual oder nur bei dingen wo ihr euch sicher seit dass das jemand durchaus mal überschreiben will.

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

wenn es eventuell einmal sein könnte

aber jetzt nich so ist dann mach ich das auch nciht virtual. Dies zu ändern mach ich dann wenn es benötigt wird. Das kannst du auch als YAGNI auffassen.
Im .net Framework geschieht das auch so. Einige Methoden die bisher nicht virtual waren wurden in einer neuen .net-Version als virtual markiert (Bsp. hab ich jezt keins parat für eine solche Methode, aber das lässt sich ja herausfinden 😉

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo Desert Fox,

alles was private wäre, pauschal protected zu machen, ist sicher nicht sinnvoll. Wenn es z.B. für ein Feld eine protected Property gibt, dann sollte das Feld private sein. Auch wenn bestimmte Felder durch Properties und Methoden nur in konsistenter Weise geändert werden können, wäre es kontraproduktiv, die Unterklasse direkt an den Feldern herumpfuschen zu lassen.

Bei virtual wohnen zwei Seelen ach in meiner Brust. Einerseits ist nach der Objektorientierung das einzig richtige, alle Methoden virtual zu machen. Anderseits ist es für die Evolvierbarkeit von Bibliotheken das einzig richtige, alle Methoden non-vitual zu machen. Zwischen diesen beiden Extremen muss man in der Praxis einen Mittelweg finden.

herbivore

R
96 Beiträge seit 2010
vor 13 Jahren

nach der Objektorientierung das einzig richtige, alle Methoden virtual zu machen

Finde ich auch, warum sind dann nicht per default alle Methoden virtual wie zB in Java ? Wegen des zero-overhead-principle wie in c++ ?

Anderseits ist es für die Evolvierbarkeit von Bibliotheken das einzig richtige, alle Methoden non-vitual zu machen.

Kannst du das genauer erklären ? Was hat die Evolvierbarkeit mit virtual zu tun ?

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

warum sind dann nicht per default alle Methoden virtual wie zB in Java ?

Steht im obigen Link ausführlich. Auch die 2. Frage wird darin erklärt. Wenns nicht virtual ist dann gibts nur 1 Methode die du anschauen musst und weist was passiert.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo Runnable,

wie gfoidl schon sagt, steht alles in obigem Link. Die entscheiden Punkte habe ich hier aber trotzdem mal zitiert:

warum sind dann nicht per default alle Methoden virtual wie zB in Java ?

There are several reasons. One is performance.

Ein weitere wichtiger Punkt ist gleichzeitig die Antwort auf deine nächste Frage:

Was hat die Evolvierbarkeit mit virtual zu tun ?

When we make something virtual in a platform, we're making an awful lot of promises about how it evolves in the future. For a non-virtual method, we promise that when you call this method, x and y will happen. When we publish a virtual method in an API, we not only promise that when you call this method, x and y will happen. We also promise that when you override this method, we will call it in this particular sequence with regard to these other ones and the state will be in this and that invariant.

Every time you say virtual in an API, you are creating a call back hook. As an OS or API framework designer, you've got to be real careful about that. You don't want users overriding and hooking at any arbitrary point in an API, because you cannot necessarily make those promises. And people may not fully understand the promises they are making when they make something virtual.

Mit anderen Worten: virtual erschwert die Änderbarkeit/Weiterentwickelbarkeit von Bibliotheken.

herbivore

H
116 Beiträge seit 2008
vor 13 Jahren

Moin!

(...) Im .net Framework geschieht das auch so. Einige Methoden die bisher nicht virtual waren wurden in einer neuen .net-Version als virtual markiert (Bsp. hab ich jezt keins parat für eine solche Methode, aber das lässt sich ja herausfinden

Dann muss ich aber auch warten, bis das Framework geändert wurde, was aus verschiedenen Gründen (Lebenszyklen, Hersteller hat die Entwicklung eingestellt etc.) nicht unbedingt wünschenswert ist.

Ich bin auch der Meinung, alles virtual zu deklarieren. Wenn es dann wirklich mal nicht sein soll, kann ich die Klasse ja versiegeln.

Hinrich

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo hinrich,

wenn man alle Klassen (also sowohl Ober- als auch Unterklasse) selbst schreibt, hat man so oder so kein Problem. Wenn man sich dafür entscheidet, alle Methoden standardmäßig non-virtual zu machen und man später in einer Unterklasse doch benötigt, dass eine Methode der Oberklasse virtuell ist, dann macht man sie eben nachträglich virtuell. Wenn man sich dafür entscheidet, alle Methoden standardmäßig virtual zu machen und eine solche Methode in einer Unterklasse tatsächlich in einer Weise überschrieben wird, bei der es darauf ankommt, wann und wo die Oberkasse die Methode aufruft und man später diese Methode doch aus der Oberklasse noch an weiteren oder weniger Stellen aufrufen muss als bisher und dadurch die Unterklasse "gebrochen" wird, dann passt man die Unterklasse eben entsprechend an.

Probleme entstehen erst da, wo Unter- und Oberklasse nicht in einer Hand liegen. Und da ist es dann doch wesentlich sicher und hält für den Entwickler der Bibliothek (also der Oberklassen) den Entwicklungspfad offen, wenn man die Methoden - ja, leider entgegen der reine Lehre der OO - standardmäßig non-virtual macht.

herbivore

1.552 Beiträge seit 2010
vor 13 Jahren

Probleme entstehen erst da, wo Unter- und Oberklasse nicht in einer Hand liegen.

Ja vor allem dann ein der Programmierer der Oberklasse alles virtual macht und man dann eine funktionierende Unterklasse besitzt, die dann von der anderen dll aufgerufen wird. Sollte sich dann eine Methode von virutal nach nicht virtual ändern, kann man sich schon mal wundern wieso die eigene Methode nicht mehr aufgerufen wird.

Gruß
Michael

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

Gelöschter Account
vor 13 Jahren

Sollte sich dann eine Methode von virutal nach nicht virtual ändern, kann man sich schon mal wundern wieso die eigene Methode nicht mehr aufgerufen wird.

Das würde nicht compilieren.

1.552 Beiträge seit 2010
vor 13 Jahren

Stimmt, aber jeder weiß wie das nervig ist, wenn man dann in allen Klassen die von der besagten ableiten in allen geändertern Methoden "new" schreiben muss. Was dann auch nicht das Problem des nicht mehr funktionierenden Programmes löst. Noch mehr nerven dürfte eine Änderung eines Interfaces, was jedoch hier nicht zur Debatte steht.
Dies jedoch untermauert die Tatsache dass man sich beim erstellen der Klasse die dann auch die Masse verwenden sollte sich ein gutes Design einfallen lässt.

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

Gelöschter Account
vor 13 Jahren

Das "new" in der Methodensignatur löst hier weder das Problem (weil die Methode ja nciht mehr aufgerufen wird) noch ist das in irgendeiner erdachten form ein hauch einer lösung. Wenn man methoden verwendet, die plötzlich nicht mehr virtual sind, dann muss man zwangsläufig ein Refactoring durchführen... und meist ein umfassendes.

4.939 Beiträge seit 2008
vor 13 Jahren

In C++ gibt es dafür extra das "non-virtual interface idiom" (NVI), manchmal auch "template method" genannt: Non-Virtual Interface

Und ob es sinnvoll ist, dieses auch in C# zu verwenden, wurde z.B. bei Is the Non-Virtual Interface (NVI) idiom as useful in C# as in C++? diskutiert.

Ich persönlich bevorzuge auch die öffentliche Schnittstelle nur aus nicht-virtuellen Methoden bestehen zu lassen und dort dann 'protected virtual'-Methoden aufzurufen.

(In C++ ist es sogar möglich virtuelle Methoden als 'private' zu deklarieren, so daß diese nicht von den vererbten Klassen aufgerufen werden können - in C# müssen virtuelle Methoden jedoch immer mindestens 'protected' deklariert werden.)

H
116 Beiträge seit 2008
vor 13 Jahren

Moin!

(...) Probleme entstehen erst da, wo Unter- und Oberklasse nicht in einer Hand liegen. Und da ist es dann doch wesentlich sicher und hält für den Entwickler der Bibliothek (also der Oberklassen) den Entwicklungspfad offen, wenn man die Methoden - ja, leider entgegen der reine Lehre der OO - standardmäßig non-virtual macht.

Imho gelangen wir da mehr in eine philosophische Debatte. Ich denke, wenn ich eine Unterklasse auf Basis einer Oberklasse entwickle, dann spielt die Version der Oberklasse eine entscheidende Rolle. Niemand wird erwarten dürfen, dass ein Framework nach einem Versionssprung identisch ansprechbar sein wird (wobei veraltete Funktionen ja niemals binär abgeschaltet werden).

Und dem Entwickler der Oberklasse kann und muss es eigentlich egal sein, was wer auch immer wo auch immer was für eine Unterklasse auch immer entwickelt.

Hinrich

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo hinrich,

Niemand wird erwarten dürfen, dass ein Framework nach einem Versionssprung identisch ansprechbar sein wird

Das sehe ich nicht ganz so. Stichwort: Kompatibilität.
Wenn in einem API etwas veröffentlicht wird stellt das ja quasi einen Vertrag dar und die Clients des API verlassen - mit gutem Recht - auf das was vertraglich zugesichert wird. Wenn in der nächsten Version des API dieses nicht mehr identisch ansprechbar ist wäre das ein Vertragsbruch.

Nimm als Beispiel das .net Framework her. In jeder Version lässt sich ein bestehendes API gleich ansprechen bzw. so dass bestehender Code nach wie vor korrekt funktioniert. Das API wird erweitert/verbessert/etc. aber die Schnittstellen müssen erhalten bleiben.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo hinrich,

Niemand wird erwarten dürfen, dass ein Framework nach einem Versionssprung identisch ansprechbar sein wird

das sehe ich vollkommen anders. Wenn man für die eigenen Projekte eine Bibliothek einsetzt, also z.B. das .NET-Framework, dann kann man mit Fug und Recht erwarten, dass die eigenen Programm auch mit einer neuen Version des Frameworks laufen. Die bestmögliche Aufwärtskompatibilität von Bibliotheken sicherzustellen, ist wichtig und auch üblich. Es wäre überhaupt nicht zu verantworten, wenn die Autoren von Bibliotheken das anders handhaben würden. Stell dir vor, Microsoft würde nicht so vorgehen und Hunderttausende wenn nicht gar Millionen von Anwendungen würden aufgrund von Breaking Changes nicht mehr laufen. Das ist überhaupt keine philosophische Debatte, sondern eine Debatte über Praktikabilität und höchst reale, spürbare, praktische Auswirkungen.

Und dem Entwickler der Oberklasse kann und muss es eigentlich egal sein, was wer auch immer wo auch immer was für eine Unterklasse auch immer entwickelt.

Sicher sollte der Entwickler der Oberklasse versuchen, dem Entwickler der Unterklasse zu ermöglichen, seine Ziele zu erreichen, egal was das Ziel des Entwickler der Unterklasse ist. Das konkrete Ziel geht den Entwickler der Oberklasse in der Tat nichts an. Aber der Entwickler der Oberklasse trägt die Verantwortung, dass er keine Breaking Chances durchführt. Und das ist für ihn deutlich einfacher, wenn alle oder möglichst wenige Methoden non-virtual sind.

herbivore

H
116 Beiträge seit 2008
vor 13 Jahren

Moin herbivore & gfoidl!

Niemand wird erwarten dürfen, dass ein Framework nach einem Versionssprung identisch ansprechbar sein wird

(...) Wenn man für die eigenen Projekte eine Bibliothek einsetzt, also z.B. das .NET-Framework, dann kann man mit Fug und Recht erwarten, dass die eigenen Programm auch mit einer neuen Version des Frameworks laufen. (...)

Dann habe ich mich vielleicht etwas missverständlich ausgedrückt: Kompatibilität ist in Grenzen richtig und wichtig. Aber eben in Grenzen. Wenn ich ein Framework einsetze, ob nun .NET oder sonst was, so erwarte ich, dass das, was ich unter 3.0 in der API zur Verfügung hatte, auch in der 3.x da ist. Vielleicht könnte ich auch noch erwarten, dass es mit identischem Verhalten in einer Version 4.x vorhanden ist. Aber in einer 5.x würde ich es nicht mehr unbedingt erwarten.

Auch Microsoft geht so vor, denn ich glaube nicht (ohne es probiert zu haben), dass Word 6.0 unter Windows 7 laufen würde (macht auch nicht wirklich Sinn). Auch glaube ich nicht, dass in der API von Windows noch alle Funktionen aus Windows 1.0 oder 3.11 in unveränderter Form verfügbar sind.

Soweit ich das mal gelernt habe, implementieren Bibliotheken Schnittstellen in einer Version, meinetwegen 1.0, erweitern die Schnittstelle über 1.1 bis 1.8, stellen dieses oder jenes ab 1.9 als deprecated dar, halten diesen Status über den 2.xer-Zyklus und entfernen diese dann im 3.x-Zyklus. Solche Versionierung ist sinnvoll und die Entfernung von Schnittstellen stellt imho mitnichten einen Vertragsbruch dar.

Hinrich

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo hinrich,

dass sehe ich wie gesagt anders. In der MSDN kannst du z.B. an verschiedenen Stellen sowas lesen wie:

Obwohl ToolStripDropDown und ToolStripDropDownMenu Funktionen des Menu-Steuerelements früherer Versionen ersetzen und erweitern, kann Menu aus Gründen der Abwärtskompatibilität und zur künftigen Verwendung beibehalten werden.

Und selbst Deprected/Obsolete bedeutet nicht, dass der Code/Member/Typ irgendwann rausfliegt.

The .NET Framework and the common language runtime strive to support backward compatibility (allowing applications that were developed with one version of the .NET Framework to run on the next version of the .NET Framework). This makes it difficult to simply remove a type or a type member. Instead, the .NET Framework indicates that a type or a type member should no longer be used by marking it as obsolete or deprecated. Deprecating a type or a member involves marking it so that developers are aware it will go away and have time to respond to its removal. However, existing code that uses the type or member continues to run in the new version of the .NET Framework.

herbivore