La palabra clave virtual se utiliza para modificar un método, propiedad, indexador o declaración de evento, y permitir que se anule en una clase derivada. Por ejemplo, este método puede ser reemplazado por cualquier clase que lo herede: use el nuevo modificador para ocultar explícitamente un miembro heredado de una clase base. Para ocultar un miembro heredado, declárelo en la clase derivada con el mismo nombre y modifíquelo con el nuevo modificador.
Todo esto tiene que ver con el polimorfismo. Cuando se llama a un método virtual en una referencia, el tipo real de objeto al que se refiere la referencia se utiliza para decidir qué implementación de método utilizar. Cuando un método de una clase base se reemplaza en una clase derivada, se usa la versión en la clase derivada, incluso si el código de llamada no "sabía" que el objeto era una instancia de la clase derivada. Por ejemplo:
public class Base
{
public virtual void SomeMethod()
{
}
}
public class Derived : Base
{
public override void SomeMethod()
{
}
}
...
Base d = new Derived();
d.SomeMethod();
terminará llamando a Derived.SomeMethod si eso anula Base.SomeMethod.
Ahora, si usa la palabra clave new en lugar de anular , el método de la clase derivada no anula el método de la clase base, simplemente lo oculta. En ese caso, codifique como este:
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();
Primero llamará Base.SomeOtherMethod, luego Derived.SomeOtherMethod. Son efectivamente dos métodos completamente separados que tienen el mismo nombre, en lugar de que el método derivado anule el método base.
Si no especifica new o overrides, la salida resultante es la misma que si hubiera especificado new, pero también recibirá una advertencia del compilador (ya que es posible que no sepa que está ocultando un método en la clase base método, o de hecho puede haber querido anularlo, y simplemente se olvidó de incluir la palabra clave).
Una declaración de propiedad primordial puede incluir el modificador sellado . El uso de este modificador evita que una clase derivada anule aún más la propiedad. Los accesos de una propiedad sellada también están sellados.
Derivedobjeto y almacenando la referencia en unaBasevariable. Esto es válido porque unDerivedobjeto también es unBaseobjeto. Eso es como decir que necesitamos una "persona" para que tengamos a "Johnny" que resulta ser una persona. Mismo trato aquí.Base b = new Derived()establece queBasese puede acceder a una clase a través de unaDerived classreferencia porquederived classes una especialización de su clase base.Derivedlas clases pueden realizar todas las operaciones (por ejemplo, invocar métodos de clase base, etc. ) quebase classpuede hacer. PeroBase classno puede realizar las operaciones queDerived classpuede hacer. EntoncesDerived d = new Base()no es correcto peroBase b = new Derived()es correcto.newmodificador parahide a base class method? En el segundo ejemplo, la llamadab.SomeOtherMethod()invoca la implementación de la clase base (se podría decir que ha ocultado el método de la clase derivada). Si ese es un ejemplo típico de uso, entoncesnewparece que se usa cuando la persona que llama tiene la intención de tener una variable de acompile-time typepara usar su método, y no el método de cualquieraruntime typesque se le pueda asignar.Cualquier método puede ser reemplazable (=
virtual) o no. La decisión la toma quien define el método: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"; } }Ahora puede anular los métodos que se pueden anular:
class Friend : Person { public Friend() : this("generic name") { } public Friend(String name) { this._name = name; } // override Person.GetName: public override String GetName() { return _name; } }Pero no puede anular el
GetPersonTypemétodo porque no es virtual.Creemos dos instancias de esas clases:
Person person = new Person(); Friend friend = new Friend("Onotole");Cuando
GetPersonTypese llama a un método no virtual porFiendinstancia, en realidadPerson.GetPersonTypese llama:Console.WriteLine(friend.GetPersonType()); // "person"Cuando
GetNamese llama al método virtual porFriendinstancia,Friend.GetNamese llama:Console.WriteLine(friend.GetName()); // "Onotole"Cuando
GetNamese llama al método virtual porPersoninstancia,Person.GetNamese llama:Console.WriteLine(person.GetName()); // "generic name"Cuando se llama a un método no virtual, no se busca el cuerpo del método; el compilador ya conoce el método real que debe llamarse. Mientras que con los métodos virtuales, el compilador no puede estar seguro de cuál llamar, y se busca en el tiempo de ejecución en la jerarquía de clases de abajo hacia arriba, comenzando en el tipo de instancia en la que se llama al método: porque
friend.GetNameparece que comienza en laFriendclase y lo encuentra de inmediato, para laperson.GetNameclase en que comienzaPersony lo encuentra allí.A veces crea una subclase, anula un método virtual y no desea más anulaciones hacia abajo en la jerarquía; lo usa
sealed overridepara eso (diciendo que es el último que anula el método):class Mike : Friend { public sealed override String GetName() { return "Mike"; } }Pero a veces tu amigo Mike decide cambiar su género y, por lo tanto, su nombre a Alice :) Podrías cambiar el código original o subclase Mike:
class Alice : Mike { public new String GetName() { return "Alice"; } }Aquí crea un método completamente diferente con el mismo nombre (ahora tiene dos). ¿Qué método y cuándo se llama? Depende de cómo lo llames:
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"Cuando lo llamas desde
Alicela perspectiva de, llamasAlice.GetName, cuando desdeMike, llamasMike.GetName. Aquí no se realiza ninguna búsqueda en tiempo de ejecución, ya que ambos métodos no son virtuales.Siempre puede crear
newmétodos, ya sea que los métodos que está ocultando sean virtuales o no.Esto también se aplica a las propiedades y eventos: se representan como métodos debajo.
fuente
De forma predeterminada, un método no se puede anular en una clase derivada a menos que se declare
virtual, oabstract.virtualsignifica verificar implementaciones más nuevas antes de llamar yabstractsignifica lo mismo, pero se garantiza que se anulará en todas las clases derivadas. Además, no se necesita implementación en la clase base porque se volverá a definir en otro lugar.La excepción a lo anterior es el
newmodificador. Un método no declaradovirtualoabstractpuede redefinirse con elnewmodificador en una clase derivada. Cuando se llama al método en la clase base, se ejecuta el método base, y cuando se llama en la clase derivada, se ejecuta el nuevo método. Todo lo que lasnewpalabras clave le permiten hacer es tener dos métodos con el mismo nombre en una jerarquía de clases.Finalmente, un
sealedmodificador rompe la cadena devirtualmétodos y los hace no anulables nuevamente. Esto no se usa con frecuencia, pero la opción está ahí. Tiene más sentido con una cadena de 3 clases cada una derivada de la anteriorsi
Atiene un métodovirtualoabstract, es decir ,overriddenenB, entonces también puede evitarCcambiarlo nuevamente declarándolosealedenB.sealedtambién se usa enclasses, y ahí es donde comúnmente encontrará esta palabra clave.Espero que esto ayude.
fuente
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"); } }Ahora lo primero es lo primero
Base b=new Base(); Derived d=new Derived(); b.SomeMethod(); //will always write B d.SomeMethod(); //will always write DAhora las palabras clave tienen que ver con el polimorfismo.
Base b = new Derived();virtualen la clase base y anular enDeriveddará D (polimorfismo).overridesinvirtualinBasedará error.virtualescribirá 'B' con una advertencia (porque no se realiza ningún polimorfismo).newantes de ese método simple enDerived.newLa palabra clave es otra historia, simplemente oculta la advertencia que dice que la propiedad con el mismo nombre está en la clase base.virtualonewambos son iguales excepto el nuevo modificadornewyoverrideno se puede utilizar antes del mismo método o propiedad.sealedantes de que cualquier clase o método lo bloquee para usarlo en la clase derivada y da un error de tiempo de compilación.fuente