C#: uso de palabras clave virtual+anulación frente a nuevo
¿Cuáles son las diferencias entre declarar un método en un tipo base " virtual
" y luego anularlo en un tipo secundario usando la override
palabra clave " " en lugar de simplemente usar la new
palabra clave " " al declarar el método coincidente en el tipo secundario?
Siempre encuentro que cosas como esta se entienden más fácilmente con imágenes:
De nuevo, tomando el código de joseph daigle,
public class Foo
{
public /*virtual*/ bool DoSomething() { return false; }
}
public class Bar : Foo
{
public /*override or new*/ bool DoSomething() { return true; }
}
Si luego llamas al código de esta manera:
Foo a = new Bar();
a.DoSomething();
NOTA: Lo importante es que nuestro objeto en realidad es un Bar
, pero lo estamos almacenando en una variable de tipoFoo
(esto es similar a convertirlo)
Entonces el resultado será el siguiente, dependiendo de si usaste virtual
/ override
o new
al declarar tus clases.
La palabra clave "nueva" no anula, significa un nuevo método que no tiene nada que ver con el método de la clase base.
public class Foo
{
public bool DoSomething() { return false; }
}
public class Bar : Foo
{
public new bool DoSomething() { return true; }
}
public class Test
{
public static void Main ()
{
Foo test = new Bar ();
Console.WriteLine (test.DoSomething ());
}
}
Esto imprime falso, si usó anulación, habría impreso verdadero.
(Código base tomado de Joseph Daigle)
Por lo tanto, si está haciendo un polimorfismo real, SIEMPRE DEBE ANULAR . El único lugar donde necesita usar "nuevo" es cuando el método no está relacionado de ninguna manera con la versión de la clase base.
Aquí hay un código para comprender la diferencia en el comportamiento de los métodos virtuales y no virtuales:
class A
{
public void foo()
{
Console.WriteLine("A::foo()");
}
public virtual void bar()
{
Console.WriteLine("A::bar()");
}
}
class B : A
{
public new void foo()
{
Console.WriteLine("B::foo()");
}
public override void bar()
{
Console.WriteLine("B::bar()");
}
}
class Program
{
static int Main(string[] args)
{
B b = new B();
A a = b;
a.foo(); // Prints A::foo
b.foo(); // Prints B::foo
a.bar(); // Prints B::bar
b.bar(); // Prints B::bar
return 0;
}
}