C# - Uso de palabras clave virtual + override vs. nuevo


¿Cuáles son las diferencias entre declarar un método en un tipo base "virtual" y luego sobrescribirlo en un tipo secundario usando la palabra clave "override" en lugar de simplemente usar la palabra clave "new" al declarar el método coincidente en el tipo secundario?

Author: i3ensays, 2008-10-02

9 answers

La palabra clave "new" 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 false, si ha utilizado override habría impreso true.

(Código base tomado de Joseph Daigle)

Por lo tanto, si está haciendo polimorfismo real, SIEMPRE DEBE ANULAR. El único lugar donde necesita usar " new " es cuando el método no está relacionado de ninguna manera con la versión de la clase base.

 172
Author: albertein,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-09 16:56:36

Siempre encuentro cosas como estas más fáciles de entender 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 es en realidad un Bar, pero estamos almacenar en una variable de tipo Foo (esto es similar a la colada)

Entonces el resultado será el siguiente, dependiendo de si utilizó virtual/override o new al declarar su clase.

Virtual / Override Explicación

 217
Author: Orion Edwards,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-08 14:08:24

Aquí hay un código para entender 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;
    }
}
 40
Author: Franci Penov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-01 22:15:01

La palabra clave new en realidad crea un miembro completamente nuevo que solo existe en ese tipo específico.

Por ejemplo

public class Foo
{
     public bool DoSomething() { return false; }
}

public class Bar : Foo
{
     public new bool DoSomething() { return true; }
}

El método existe en ambos tipos. Cuando usas reflexión y obtienes los miembros de type Bar, en realidad encontrarás 2 métodos llamados DoSomething() que se ven exactamente iguales. Al usar new efectivamente oculta la implementación en la clase base, de modo que cuando las clases derivan de Bar (en mi ejemplo) la llamada al método a base.DoSomething() va a Bar y no Foo.

 18
Author: Joseph Daigle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-01 22:15:24

Virtual / override le dice al compilador que los dos métodos están relacionados y que en algunas circunstancias cuando usted pensaría que está llamando al primer método (virtual), en realidad es correcto llamar al segundo método (sobrescrito) en su lugar. Este es el fundamento del polimorfismo.

(new SubClass() as BaseClass).VirtualFoo()

Llamará al método VirtualFoo() anulado de la SubClase.

New le dice al compilador que está agregando un método a una clase derivada con el mismo nombre que un método clase baja, pero no tienen relación entre sí.

(new SubClass() as BaseClass).NewBar()

Llamará al método NewBar() de la clase base, mientras que:

(new SubClass()).NewBar()

Llamará al método NewBar() de la SubClase.

 9
Author: Wedge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-01 22:24:02

Más allá de los detalles técnicos, creo que el uso de virtual/override comunica mucha información semántica sobre el diseño. Cuando declara un método virtual, indica que espera que las clases de implementación quieran proporcionar sus propias implementaciones no predeterminadas. Omitiendo esto en una clase base, igualmente, declara la expectativa de que el método predeterminado debería ser suficiente para todas las clases implementadoras. Del mismo modo, se pueden usar declaraciones abstractas para forzar a las clases implementadoras a proporcionar su propia implementación. De nuevo, creo que esto comunica mucho sobre cómo el programador espera que se use el código. Si estuviera escribiendo tanto la base como la implementación de las clases y me encontrara usando new, reconsideraría seriamente la decisión de no hacer que el método sea virtual en el padre y declararía mi intención específicamente.

 8
Author: tvanfosson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-01 22:20:31

La diferencia entre la palabra clave override y la palabra clave new es que la primera hace overriding de método y la última hace ocultación de método.

Echa un vistazo a los siguientes enlaces para obtener más información...

MSDN and Other

 4
Author: Nescio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-01 22:11:50
  • new la palabra clave es para Ocultar. - significa que está ocultando su método en tiempo de ejecución. La salida se basará en el método de clase base.
  • override para anular. - significa que está invocando su método de clase derivada con la referencia de clase base. La salida se basará en el método de clase derivado.
 3
Author: Chetan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-11 15:57:55

Mi versión de la explicación viene de usar propiedades para ayudar a entender las diferencias.

override es bastante simple, ¿verdad ? El tipo subyacente anula el del padre.

new es tal vez el error (para mí fue). Con propiedades es más fácil de entender:

public class Foo
{
    public bool GetSomething => false;
}

public class Bar : Foo
{
    public new bool GetSomething => true;
}

public static void Main(string[] args)
{
    Foo foo = new Bar();
    Console.WriteLine(foo.GetSomething);

    Bar bar = new Bar();
    Console.WriteLine(bar.GetSomething);
}

Usando un depurador puedes notar que Foo foo tiene 2 GetSomething propiedades, ya que en realidad tiene 2 versiones de la propiedad, Foo ' s y Bar's, y saber cuál usar, c# "elige" la propiedad para el tipo actual.

Si quisieras usar la versión de la Barra, habrías usado override o usar Foo foo en su lugar.

Bar bar sólo tiene 1, como se quiere completamente nuevo comportamiento para GetSomething.

 1
Author: Dror Weiss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-06 07:30:48