Diferencia entre nuevo y anulación

Preguntándose cuál es la diferencia entre los siguientes:

Caso 1: Clase base

public void DoIt(); 

Caso 1: clase heredada

 public new void DoIt(); 

Caso 2: Clase base

 public virtual void DoIt(); 

Caso 2: clase heredada

 public override void DoIt(); 

Ambos casos 1 y 2 parecen tener el mismo efecto en función de las pruebas que he ejecutado. ¿Hay alguna diferencia, o una forma preferida?

El modificador de anulación se puede usar en métodos virtuales y se debe usar en métodos abstractos. Esto indica que el comstackdor usa la última implementación definida de un método. Incluso si se llama al método en una referencia a la clase base, usará la implementación anulándola.

 public class Base { public virtual void DoIt() { } } public class Derived : Base { public override void DoIt() { } } Base b = new Derived(); b.DoIt(); // Calls Derived.DoIt 

llamará Derived.DoIt si eso anula Base.DoIt .

El nuevo modificador indica al comstackdor que use su implementación de clase secundaria en lugar de la implementación de la clase padre. Cualquier código que no hace referencia a su clase, pero la clase principal utilizará la implementación de la clase padre.

 public class Base { public virtual void DoIt() { } } public class Derived : Base { public new void DoIt() { } } Base b = new Derived(); Derived d = new Derived(); b.DoIt(); // Calls Base.DoIt d.DoIt(); // Calls Derived.DoIt 

Primero llamará a Base.DoIt , luego a Derived.DoIt . Son efectivamente dos métodos completamente separados que tienen el mismo nombre, en lugar del método derivado que reemplaza el método base.

Fuente: blog de Microsoft

virtual : indica que un método puede ser anulado por un heredero

anular : anula la funcionalidad de un método virtual en una clase base, proporcionando diferentes funcionalidades.

nuevo : oculta el método original (que no tiene que ser virtual), proporcionando diferentes funcionalidades. Esto solo debe usarse donde sea absolutamente necesario.

Cuando ocultas un método, aún puedes acceder al método original mediante conversión a la clase base. Esto es útil en algunos escenarios, pero peligroso.

En el primer caso, está ocultando la definición en la clase principal. Esto significa que solo se invocará cuando se trate del objeto como clase hija. Si convierte la clase a su tipo principal, se invocará el método del padre. En la segunda instancia, el método se reemplaza y se invocará independientemente de si el objeto se convierte como la clase secundaria o secundaria.

intente seguir: (case1)

 ((BaseClass)(new InheritedClass())).DoIt() 

Editar: la anulación virtual + se resuelve en tiempo de ejecución (por lo tanto, la anulación realmente anula los métodos virtuales), mientras que la nueva solo crea un nuevo método con el mismo nombre y oculta la anterior, se resuelve en tiempo de comstackción -> su comstackdor llamará al método ‘ ve ‘

En el caso 1, si utilizó el método DoIt () de la clase heredada, mientras que el tipo se declara como la clase base, verá la acción de la clase base incluso.

 /* Results Class1 Base1 Class2 Class2 */ public abstract class Base1 { public void DoIt() { Console.WriteLine("Base1"); } } public class Class1 : Base1 { public new void DoIt() { Console.WriteLine("Class1"); } } public abstract class Base2 { public virtual void DoIt() { Console.WriteLine("Base2"); } } public class Class2 : Base2 { public override void DoIt() { Console.WriteLine("Class2"); } } static void Main(string[] args) { var c1 = new Class1(); c1.DoIt(); ((Base1)c1).DoIt(); var c2 = new Class2(); c2.DoIt(); ((Base2)c2).DoIt(); Console.Read(); } 

La diferencia entre los dos casos es que en el caso 1, el método base DoIt no se anula, simplemente se oculta. Lo que esto significa es que dependiendo del tipo de la variable depende de qué método se llamará. Por ejemplo:

 BaseClass instance1 = new SubClass(); instance1.DoIt(); // Calls base class DoIt method SubClass instance2 = new SubClass(); instance2.DoIt(); // Calls sub class DoIt method 

Esto puede ser realmente confuso y da como resultado un comportamiento no esperado y debe evitarse si es posible. Entonces, la forma preferida sería el caso 2.

Mi forma de tener en cuenta ambas palabras clave es que son opuestas entre sí.

override : virtual palabra clave virtual debe definirse para anular el método. El método que utiliza la palabra clave override independientemente del tipo de referencia (referencia de la clase base o clase derivada) si se crea una instancia con la clase base, se ejecuta el método de la clase base. De lo contrario, se ejecuta el método de la clase derivada.

new : si la palabra clave es usada por un método, a diferencia de la palabra clave override , el tipo de referencia es importante. Si se crea una instancia con clase derivada y el tipo de referencia es clase base, se ejecuta el método de clase base. Si se instancia con clase derivada y el tipo de referencia es clase derivada, se ejecuta el método de clase derivada. A saber, es el contraste de la palabra clave override . En passant, si olvida u omite agregar una nueva palabra clave al método, el comstackdor se comporta de manera predeterminada a medida que se usa una new palabra clave.

 class A { public string Foo() { return "A"; } public virtual string Test() { return "base test"; } } class B: A { public new string Foo() { return "B"; } } class C: B { public string Foo() { return "C"; } public override string Test() { return "derived test"; } } 

Llamar al principal:

 A AClass = new B(); Console.WriteLine(AClass.Foo()); B BClass = new B(); Console.WriteLine(BClass.Foo()); B BClassWithC = new C(); Console.WriteLine(BClassWithC.Foo()); Console.WriteLine(AClass.Test()); Console.WriteLine(BClassWithC.Test()); 

Salida:

 A B B base test derived test 

Si se utiliza la override palabras clave en la clase de derivación, entonces se reemplaza el método principal.

Si se utiliza Palabra clave new en la clase derivada, derive el método oculto por el método principal.

El siguiente artículo está en vb.net, pero creo que la explicación sobre nuevas anulaciones es muy fácil de entender.

https://www.codeproject.com/articles/17477/the-dark-shadow-of-overrides

En algún punto del artículo, hay esta oración:

En general, Shadows asume que se invoca la función asociada con el tipo, mientras que Overrides asume que se ejecuta la implementación del objeto.

La respuesta aceptada a esta pregunta es perfecta, pero creo que este artículo proporciona buenos ejemplos para agregar un mejor significado acerca de las diferencias entre estas dos palabras clave.

De todos ellos, nuevo es el más confuso. A través de la experimentación, la nueva palabra clave es como ofrecer a los desarrolladores la opción de anular la implementación de clase heredada con la implementación de la clase base al definir explícitamente el tipo. Es como pensar al revés.

En el ejemplo siguiente, el resultado arrojará el “Resultado derivado” hasta que el tipo se defina explícitamente como prueba de BaseClass, solo entonces se devolverá el “Resultado base”.

 class Program { static void Main(string[] args) { var test = new DerivedClass(); var result = test.DoSomething(); } } class BaseClass { public virtual string DoSomething() { return "Base result"; } } class DerivedClass : BaseClass { public new string DoSomething() { return "Derived result"; } } 

La diferencia funcional no se mostrará en estas pruebas:

 BaseClass bc = new BaseClass(); bc.DoIt(); DerivedClass dc = new DerivedClass(); dc.ShowIt(); 

En este ejemplo, el Doit que se llama es el que espera que se llame.

Para ver la diferencia tienes que hacer esto:

 BaseClass obj = new DerivedClass(); obj.DoIt(); 

Verá si ejecuta esa prueba que en el caso 1 (como lo definió), se llama a DoIt() en BaseClass , en el caso 2 (como lo definió), se llama a DoIt() en DerivedClass .

Tenía la misma pregunta y es realmente confusa, debería considerar que las palabras clave de anulación y nuevas funcionan solo con objetos de tipo clase base y valor de clase derivada. En este caso, solo verá el efecto de sobrescribir y el nuevo: Entonces, si tiene la class A y B , B hereda de A , entonces crea una instancia de un objeto como este:

 A a = new B(); 

Ahora, los métodos de llamada tendrán en cuenta su estado. Override : significa que amplía la función del método, luego usa el método en la clase derivada, mientras que new le dice al comstackdor que oculte el método en la clase derivada y use el método en la clase base. Aquí hay una muy buena vista de ese tema:

https://msdn.microsoft.com/EN-US/library/ms173153%28v=VS.140,d=hv.2%29.aspx?f=255&MSPPError=-2147217396

En el primer caso llamará al método DoIt () derivado de la clase porque la nueva palabra clave oculta el método DoIt () de la clase base.

En el segundo caso llamará a DoIt () anulado

  public class A { public virtual void DoIt() { Console.WriteLine("A::DoIt()"); } } public class B : A { new public void DoIt() { Console.WriteLine("B::DoIt()"); } } public class C : A { public override void DoIt() { Console.WriteLine("C::DoIt()"); } } 

deja crear instancia de estas clases

  A instanceA = new A(); B instanceB = new B(); C instanceC = new C(); instanceA.DoIt(); //A::DoIt() instanceB.DoIt(); //B::DoIt() instanceC.DoIt(); //B::DoIt() 

Todo se espera arriba. Deje set instanceB y instanceC a instanceA y llame al método DoIt () y verifique el resultado.

  instanceA = instanceB; instanceA.DoIt(); //A::DoIt() calls DoIt method in class A instanceA = instanceC; instanceA.DoIt();//C::DoIt() calls DoIt method in class C because it was overriden in class C