Cualquier método puede ser reemplazable (= virtual
) o no. La decisión la toma quien define el método:
class Person
{
public String GetPersonType()
{
return "person";
}
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;
}
public override String GetName()
{
return _name;
}
}
Pero no puede anular el GetPersonType
método porque no es virtual.
Creemos dos instancias de esas clases:
Person person = new Person();
Friend friend = new Friend("Onotole");
Cuando GetPersonType
se llama a un método no virtual por Fiend
instancia, en realidad Person.GetPersonType
se llama:
Console.WriteLine(friend.GetPersonType());
Cuando GetName
se llama al método virtual por Friend
instancia, Friend.GetName
se llama:
Console.WriteLine(friend.GetName());
Cuando GetName
se llama al método virtual por Person
instancia, Person.GetName
se llama:
Console.WriteLine(person.GetName());
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.GetName
parece que comienza en la Friend
clase y lo encuentra de inmediato, para la person.GetName
clase en que comienza Person
y 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 override
para 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());
Console.WriteLine(((Mike)alice).GetName());
Cuando lo llamas desde Alice
la perspectiva de, llamas Alice.GetName
, cuando desde Mike
, llamas Mike.GetName
. Aquí no se realiza ninguna búsqueda en tiempo de ejecución, ya que ambos métodos no son virtuales.
Siempre puede crear new
mé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.