2008-10-01 18 views
181

¿Cuáles son las diferencias entre declarar un método en un tipo base "virtual" y luego anulando en un tipo de niño que usa el "override" palabra clave en lugar de simplemente usar el "new" palabra clave al declarar el método de coincidencia en el tipo de niño?C# - Palabra clave de uso + virtual anulación contra nuevo

+3

[MSDN] (http://msdn.microsoft.com/en-us/library/435f1dw2%28v=vs.80%29.aspx) dice "Usar' nuevo' crea un nuevo miembro con el mismo nombre y hace que el miembro original se oculte, mientras que 'anulación' amplía la implementación para un miembro heredado " – AminM

+0

vea esto http://stackoverflow.com/questions/17717570/why-does-calling-a-method-in-my-derived -class-call-the-base-class-method –

+0

MSDN - http://msdn.microsoft.com/en-us/library/ms173153.aspx – dayuloli

Respuesta

163

La palabra clave "nueva" no se 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 falsa, si se ha utilizado anulación habría impresa cierto.

(código base tomada de Joseph Daigle)

Por lo tanto, si usted está haciendo el polimorfismo verdadero usted DEBE siempre anulan. El único lugar donde debe usar "nuevo" es cuando el método no está relacionado de ninguna manera con la versión de la clase base.

+0

Debe revisar su código, hice los métodos estáticos (que es válido para usar la palabra clave "nueva"). Pero decidí que era más claro usar métodos de instancia. –

+1

Gracias, me perdí la parte "estática". Debería prestar más atención al futuro – albertein

+1

Tenga en cuenta que la línea Foo test = new Bar() es crucial aquí, la palabra clave new/override para los métodos determina a qué método se llama cuando coloca una barra en una variable Foo. –

18

La palabra clave new realmente 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 utiliza el reflejo y obtiene los miembros del tipo Bar, en realidad encontrará 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 se derivan de Bar (en mi ejemplo), la llamada al método base.DoSomething() va a Bar y no a Foo.

4

La diferencia entre la palabra clave de anulación y la palabra clave nueva es que la primera anula el método y luego oculta el método.

Salida los enlaces siguientes iniciales para más información ...

MSDN y Other

40

Aquí hay algo de 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; 
    } 
} 
+0

gracias por esto, pero ¿por qué usar' new' para "ocultar" el método base, cuando simplemente no se usa la anulación parece hacer lo mismo? – mmcrae

+0

No creo que se haya creado para evitar que se invalide la clase base. Creo que fue creado para evitar el conflicto de nombres ya que no puede anular un método que no es 'virtual' y el compilador se quejará si ve el mismo nombre de función en una clase" línea de sangre "sin la firma' virtual' – mr5

8

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

+0

La técnica las explicaciones de la nueva anulación son sólidas, pero esta respuesta parece ser la más útil para guiar a los desarrolladores a usar. – Sully

9

virtual/override le dice al compilador que los dos métodos están relacionados y que, en algunas circunstancias en las que se podría pensar que está llamando el primer método (virtual) en realidad es correcto llamar el segundo método (anulado) en su lugar. Esta es la base del polimorfismo.

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

Llamará al método VirtualFoo() modificado 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 en la clase base, pero no tienen ninguna relación entre ellos.

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

llamaremos método del BaseClass NewBar(), Considerando lo siguiente:

(new SubClass()).NewBar() 

llamaremos método de la subclase NewBar().

+0

me gusta mucho esta frase "dice el compilador" –

+0

"fundación del polimorfismo" es otro refrán con clase :) –

214

siempre encuentro cosas como esto más fácil de entender con imágenes:

Una vez más, 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 a continuación, llama al código como este:

Foo a = new Bar(); 
a.DoSomething(); 

NOTA: Lo importante es que nuestro objeto es en realidad un Bar, pero estamos almacenándolo en una variable o f tipo Foo (esto es similar a lanzarlo)

A continuación, el resultado será el siguiente, dependiendo de si usó virtual/o overridenew al declarar sus clases.

Virtual/Override Explanation

+3

Gracias .... pero ¿podría explicar un poco sobre la imagen anterior con respecto al casting que dijo? – odiseh

+0

¡Vaya! Si olvidé agregar estas pocas líneas a mi anterior. comment: ¿te refieres a virtual/overriding y no vitual/new se usan solo para el concepto de polimorfismo y cuando simplemente declaras una variable (no usando casting) no significan? Gracias de nuevo. – odiseh

+0

esta respuesta es exactamente lo que estaba buscando. El único problema que tuve es que las imágenes de flickr están bloqueadas en mi lugar de trabajo, así que tuve que acceder a ellas a través de mi teléfono ... – mezoid

3
  • new 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 derivado con la referencia de la clase base. La salida se basará en el método de clase derivado.
1

Mi versión de la explicación proviene del uso de propiedades para ayudar a entender las diferencias.

override es lo suficientemente simple, ¿no? El tipo subyacente reemplaza el principal.

new es tal vez el engañoso (para mí lo fue). Con propiedades que 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); 
} 

El uso de un depurador se puede observar que Foo foo tiene GetSomething propiedades, ya que en realidad tiene 2 versiones de la propiedad, Foo 's y Bar' s, y conocer cuál usar, C# "elige" la propiedad para el tipo actual.

Si desea utilizar la versión de la barra, habría utilizado la anulación o el uso Foo foo en su lugar.

Bar bar sólo tiene , ya que quiere completamente nuevo comportamiento para GetSomething.

Cuestiones relacionadas