Das virtuelle Schlüsselwort wird verwendet, um eine Methode, eine Eigenschaft, einen Indexer oder eine Ereignisdeklaration zu ändern und das Überschreiben in einer abgeleiteten Klasse zu ermöglichen. Diese Methode kann beispielsweise von jeder Klasse überschrieben werden, die sie erbt: Verwenden Sie den neuen Modifikator, um ein von einer Basisklasse geerbtes Mitglied explizit auszublenden. Um ein geerbtes Mitglied auszublenden, deklarieren Sie es in der abgeleiteten Klasse mit demselben Namen und ändern Sie es mit dem neuen Modifikator.
Das hat alles mit Polymorphismus zu tun. Wenn eine virtuelle Methode für eine Referenz aufgerufen wird, wird anhand des tatsächlichen Typs des Objekts, auf das sich die Referenz bezieht, entschieden, welche Methodenimplementierung verwendet werden soll. Wenn eine Methode einer Basisklasse in einer abgeleiteten Klasse überschrieben wird, wird die Version in der abgeleiteten Klasse verwendet, auch wenn der aufrufende Code nicht "wusste", dass das Objekt eine Instanz der abgeleiteten Klasse ist. Zum Beispiel:
public class Base
{
public virtual void SomeMethod()
{
}
}
public class Derived : Base
{
public override void SomeMethod()
{
}
}
...
Base d = new Derived();
d.SomeMethod();
wird am Ende Derived.SomeMethod aufrufen, wenn dies Base.SomeMethod überschreibt.
Wenn Sie jetzt das neue Schlüsselwort anstelle des Überschreibens verwenden , überschreibt die Methode in der abgeleiteten Klasse die Methode in der Basisklasse nicht, sondern verbirgt sie lediglich. In diesem Fall Code wie folgt:
public class Base
{
public virtual void SomeOtherMethod()
{
}
}
public class Derived : Base
{
public new void SomeOtherMethod()
{
}
}
...
Base b = new Derived();
Derived d = new Derived();
b.SomeOtherMethod();
d.SomeOtherMethod();
Ruft zuerst Base.SomeOtherMethod und dann Derived.SomeOtherMethod auf. Es handelt sich effektiv um zwei völlig getrennte Methoden, die zufällig denselben Namen haben, und nicht um die abgeleitete Methode, die die Basismethode überschreibt.
Wenn Sie weder neu noch Überschreibungen angeben, ist die resultierende Ausgabe dieselbe wie bei Angabe von neu, es wird jedoch auch eine Compiler-Warnung angezeigt (da Sie möglicherweise nicht wissen, dass Sie eine Methode in der Basisklasse ausblenden Methode, oder vielleicht wollten Sie sie überschreiben und haben nur vergessen, das Schlüsselwort anzugeben).
Eine übergeordnete Eigenschaftsdeklaration kann den versiegelten Modifikator enthalten. Die Verwendung dieses Modifikators verhindert, dass eine abgeleitete Klasse die Eigenschaft weiter überschreibt. Die Accessoren eines versiegelten Eigentums sind ebenfalls versiegelt.
Derived
Objekts und speichern die Referenz in einerBase
Variablen. Dies ist gültig, weil einDerived
Objekt auch ein Objekt istBase
. Das ist so, als würde man sagen, dass wir eine "Person" brauchen, damit wir "Johnny" bekommen, der zufällig eine Person ist. Gleiches Angebot hier.Base b = new Derived()
Es besagt, dass auf eineBase
Klasse durchDerived class
Referenz zugegriffen werden kann, da a einederived class
Spezialisierung ihrer Basisklasse ist.Derived
Klassen können alle Operationen ausführen (z. B. Aufrufen von Basisklassenmethoden usw. ), die a ausführenbase class
kann. Aber aBase class
kann die Operationen, die es ausführen kann, nicht ausführenDerived class
. AlsoDerived d = new Base()
nicht richtig, aberBase b = new Derived()
richtig.new
Modifikators erläuternhide a base class method
? Im zweiten Beispielb.SomeOtherMethod()
ruft der Aufruf die Basisklassenimplementierung auf (man könnte sagen, er hat die Methode der abgeleiteten Klasse ausgeblendet ). Wenn dies ein typisches Anwendungsbeispiel ist,new
scheint es verwendet zu werden, wenn der Aufrufer beabsichtigt, eine Variable von acompile-time type
zu haben, um seine Methode zu verwenden, und nicht die Methode von einerruntime types
, die ihm zugewiesen werden kann.Jede Methode kann überschreibbar sein (=
virtual
) oder nicht. Die Entscheidung trifft derjenige, der die Methode definiert:class Person { // this one is not overridable (not virtual) public String GetPersonType() { return "person"; } // this one is overridable (virtual) public virtual String GetName() { return "generic name"; } }
Jetzt können Sie die überschreibbaren Methoden überschreiben:
class Friend : Person { public Friend() : this("generic name") { } public Friend(String name) { this._name = name; } // override Person.GetName: public override String GetName() { return _name; } }
Sie können die
GetPersonType
Methode jedoch nicht überschreiben , da sie nicht virtuell ist.Erstellen wir zwei Instanzen dieser Klassen:
Person person = new Person(); Friend friend = new Friend("Onotole");
Wenn eine nicht virtuelle Methode
GetPersonType
von einerFiend
Instanz aufgerufen wird, heißt sie tatsächlichPerson.GetPersonType
:Console.WriteLine(friend.GetPersonType()); // "person"
Wenn die virtuelle Methode
GetName
von einerFriend
InstanzFriend.GetName
aufgerufen wird, heißt sie:Console.WriteLine(friend.GetName()); // "Onotole"
Wenn die virtuelle Methode
GetName
von einerPerson
InstanzPerson.GetName
aufgerufen wird, heißt sie:Console.WriteLine(person.GetName()); // "generic name"
Wenn eine nicht virtuelle Methode aufgerufen wird, wird der Methodenkörper nicht nachgeschlagen - der Compiler kennt bereits die tatsächliche Methode, die aufgerufen werden muss. Während bei virtuellen Methoden der Compiler nicht sicher sein kann, welche aufgerufen werden soll, wird er zur Laufzeit in der Klassenhierarchie von unten nach oben ab dem Instanztyp nachgeschlagen, auf den die Methode aufgerufen wird: denn
friend.GetName
er sieht abFriend
Klasse und aus findet es sofort, für denperson.GetName
Unterricht beginnt esPerson
und findet es dort.Manchmal erstellen Sie eine Unterklasse, überschreiben eine virtuelle Methode und möchten keine weiteren Überschreibungen in der Hierarchie - Sie verwenden dies
sealed override
(sagen, Sie sind der letzte, der die Methode überschreibt):class Mike : Friend { public sealed override String GetName() { return "Mike"; } }
Aber manchmal beschließt dein Freund Mike, sein Geschlecht und damit seinen Namen in Alice zu ändern :) Du kannst entweder den Originalcode ändern oder stattdessen die Unterklasse Mike:
class Alice : Mike { public new String GetName() { return "Alice"; } }
Hier erstellen Sie eine völlig andere Methode mit demselben Namen (jetzt haben Sie zwei). Welche Methode und wann wird aufgerufen? Es hängt davon ab, wie Sie es nennen:
Alice alice = new Alice(); Console.WriteLine(alice.GetName()); // the new method is called, printing "Alice" Console.WriteLine(((Mike)alice).GetName()); // the method hidden by new is called, printing "Mike"
Wenn Sie es aus
Alice
der Perspektive anrufenAlice.GetName
, rufen Sie an , wenn Sie aus der PerspektiveMike
anrufenMike.GetName
. Hier wird keine Laufzeitsuche durchgeführt, da beide Methoden nicht virtuell sind.Sie können jederzeit
new
Methoden erstellen - unabhängig davon, ob die ausgeblendeten Methoden virtuell sind oder nicht.Dies gilt auch für Eigenschaften und Ereignisse - sie werden darunter als Methoden dargestellt.
quelle
Standardmäßig kann eine Methode in einer abgeleiteten Klasse nur überschrieben werden, wenn sie deklariert ist
virtual
, oderabstract
.virtual
bedeutet , vor dem Aufruf nach neueren Implementierungen zu suchen undabstract
bedeutet dasselbe, aber es wird garantiert in allen abgeleiteten Klassen überschrieben. Außerdem ist in der Basisklasse keine Implementierung erforderlich, da sie an anderer Stelle neu definiert wird.Die Ausnahme ist der
new
Modifikator. Eine Methode, die nicht deklariert istvirtual
oderabstract
mit demnew
Modifikator in einer abgeleiteten Klasse neu definiert werden kann . Wenn die Methode in der Basisklasse aufgerufen wird, wird die Basismethode ausgeführt, und wenn sie in der abgeleiteten Klasse aufgerufen wird, wird die neue Methode ausgeführt. Allenew
Schlüsselwörter können Sie zu tun ist, haben zwei Methoden mit dem gleichen Namen in einer Klassenhierarchie.Schließlich unterbricht ein
sealed
Modifikator dievirtual
Methodenkette und macht sie nicht wieder überschreibbar. Dies wird nicht oft verwendet, aber die Option ist da. Es ist sinnvoller mit einer Kette von 3 Klassen, die jeweils von der vorherigen abgeleitet sindwenn
A
eine hatvirtual
oderabstract
Verfahren, das heißtoverridden
inB
, dann kann es auch verhindern , dassC
daraus wieder zu ändern , indem er erklärt ,sealed
inB
.sealed
wird auch in verwendetclasses
, und dort werden Sie häufig auf dieses Schlüsselwort stoßen.Ich hoffe das hilft.
quelle
public class Base { public virtual void SomeMethod() { Console.WriteLine("B"); } } public class Derived : Base { //Same method is written 3 times with different keywords to explain different behaviors. //This one is Simple method public void SomeMethod() { Console.WriteLine("D"); } //This method has 'new' keyword public new void SomeMethod() { Console.WriteLine("D"); } //This method has 'override' keyword public override void SomeMethod() { Console.WriteLine("D"); } }
Jetzt als erstes zuerst
Base b=new Base(); Derived d=new Derived(); b.SomeMethod(); //will always write B d.SomeMethod(); //will always write D
Jetzt dreht sich alles um Polymorphismus
Base b = new Derived();
virtual
in der Basisklasse und das Überschreiben inDerived
ergibt D (Polymorphismus).override
withoutvirtual
inBase
führt zu einem Fehler.virtual
'B' mit Warnung geschrieben (da kein Polymorphismus durchgeführt wird).new
vor dieser einfachen Methode inDerived
.new
Das Schlüsselwort ist eine andere Geschichte. Es verbirgt einfach die Warnung, dass die gleichnamige Eigenschaft in der Basisklasse vorhanden ist.virtual
odernew
beide sind bis auf den neuen Modifikator gleichnew
undoverride
kann nicht vor derselben Methode oder Eigenschaft verwendet werden.sealed
Bevor eine Klasse oder Methode gesperrt wird, um in der abgeleiteten Klasse verwendet zu werden, wird ein Fehler bei der Kompilierung angezeigt.quelle