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 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 por Fiendinstancia, en realidad Person.GetPersonTypese llama:
Console.WriteLine(friend.GetPersonType());
Cuando GetNamese llama al método virtual por Friendinstancia, Friend.GetNamese llama:
Console.WriteLine(friend.GetName());
Cuando GetNamese llama al método virtual por Personinstancia, Person.GetNamese 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.GetNameparece que comienza en la Friendclase y lo encuentra de inmediato, para la person.GetNameclase en que comienza Persony 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());
Console.WriteLine(((Mike)alice).GetName());
Cuando lo llamas desde Alicela 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 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.