Anulación vs escondite método [duplicado]
-
27-09-2019 - |
Pregunta
Esta pregunta ya tiene una respuesta aquí:
- Diferencia entre sombras y anulando en C #? 5 respuestas
Estoy un poco confundido acerca anulando vs ocultar un método en C #. usos prácticos de cada uno también serían apreciados, así como una explicación para cuando se podría usar cada uno.
Me gustaría saber anulando - ¿por qué dispositivo? Lo que he aprendido hasta ahora es que por overring podemos proporcionar implementación deseada a un método de una clase derivada, sin cambiar la firma.
Si no anular el método de la superclase y hago cambios en el método de la subclase, la voluntad, que modifican el método de superclase?
También estoy confundido acerca de lo siguiente: -? Lo que demuestra esto
class A
{
virtual m1()
{
console.writeline("Bye to all");
}
}
class B : A
{
override m1()
{
console.writeLine("Hi to all");
}
}
class C
{
A a = new A();
B b = new B();
a = b; (what is this)
a.m1(); // what this will print and why?
b = a; // what happens here?
}
Solución
Considere lo siguiente:
public class BaseClass
{
public void WriteNum()
{
Console.WriteLine(12);
}
public virtual void WriteStr()
{
Console.WriteLine("abc");
}
}
public class DerivedClass : BaseClass
{
public new void WriteNum()
{
Console.WriteLine(42);
}
public override void WriteStr()
{
Console.WriteLine("xyz");
}
}
/* ... */
BaseClass isReallyBase = new BaseClass();
BaseClass isReallyDerived = new DerivedClass();
DerivedClass isClearlyDerived = new DerivedClass();
isReallyBase.WriteNum(); // writes 12
isReallyBase.WriteStr(); // writes abc
isReallyDerived.WriteNum(); // writes 12
isReallyDerived.WriteStr(); // writes xyz
isClearlyDerived.WriteNum(); // writes 42
isClearlyDerived.writeStr(); // writes xyz
primordial es la manera clásica OO en el que una clase derivada puede tener un comportamiento más específico que una clase base (en algunos idiomas que no hay más remedio que hacerlo). Cuando un método virtual se llama en un objeto, entonces la versión más derivada del método se llama. Por lo tanto, a pesar de que estamos tratando con isReallyDerived
como BaseClass
continuación, se utiliza la funcionalidad definida en DerivedClass
.
Ocultación de que tenemos un método completamente diferente. Cuando llamamos WriteNum()
en isReallyDerived
entonces no hay manera de saber que hay un WriteNum()
diferente en DerivedClass
por lo que no se conoce. Sólo puede ser llamado cuando estamos tratando con el objeto como a DerivedClass
.
La mayor parte del tiempo es malo escondite. Por lo general, ya sea que usted debe tener un método como virtual si su probabilidad de ser cambiado en una clase derivada, y anularlo en la clase derivada. Sin embargo, hay dos cosas que es útil para:
-
Compatibilidad hacia adelante. Si
DerivedClass
tenía un métodoDoStuff()
, y más tardeBaseClass
fue cambiado para agregar un métodoDoStuff()
, (recuerde que pueden ser escritos por diferentes personas y existen en diferentes montajes), entonces la prohibición de escondite miembro habría repente hecha con erroresDerivedClass
sin ella cambiando. Además, si el nuevoDoStuff()
enBaseClass
era virtual, a continuación, hacer automáticamente que elDerivedClass
una anulación de los que podría conducir al método preexistente que se llama cuando no debe. Por lo tanto, es bueno que escondite es el valor predeterminado (usamosnew
para que quede claro que definitivamente desea ocultar, pero dejando fuera cueros y emite una advertencia en la compilación). -
covarianza del pobre hombre. Considere un método
Clone()
enBaseClass
que devuelve un nuevoBaseClass
que es una copia de la creada. En la anulación deDerivedClass
esto creará unDerivedClass
pero devolverlo como unaBaseClass
, que no es tan útil. Lo que podríamos hacer es tener unCreateClone()
protegido virtual que está anulado. EnBaseClass
tenemos unClone()
que devuelve el resultado de esto - y todo está bien - enDerivedClass
escondemos esto con una nuevaClone()
que devuelve unDerivedClass
. LlamandoClone()
enBaseClass
siempre devolverá una referenciaBaseClass
, que será un valor o un valorBaseClass
DerivedClass
según corresponda. LlamandoClone()
enDerivedClass
devolverá un valorDerivedClass
, que es lo que nos gustaría en ese contexto. Hay otras variantes de este principio, sin embargo hay que señalar que todos ellos son bastante raros.
Una cosa importante a nota con el segundo caso, es que hemos utilizado precisamente para esconderse Eliminar sorprende al código de llamada, ya que la persona que utiliza DerivedClass
podría esperar razonablemente su Clone()
para devolver un DerivedClass
. Los resultados de cualquiera de las formas en que se podría llamar se mantienen coherentes entre sí. La mayoría de los casos de ocultar sorpresas riesgo de introducir, por lo que generalmente son mal vistas. Esto se justifica precisamente porque resuelve el problema que se esconde a menudo introduce.
En total, esconderse a veces es necesario, con poca frecuencia útil, pero generalmente mal, así que mucho cuidado con él.
Otros consejos
primordial es cuando se proporciona una nueva aplicación override
de un método en una clase descendiente cuando se defina ese método en la clase base como virtual
.
Ocultación es cuando se proporciona una nueva implementación de un método en una clase descendiente cuando ese método es no definido en la clase base como virtual
, o cuando su nueva aplicación no especifica override
.
de ocultación es muy a menudo mal; por lo general debe tratar de no hacerlo si se puede evitar en absoluto. Escondite puede causar cosas inesperadas que suceden, porque los métodos ocultos sólo se utilizan cuando se le llama en una variable del tipo real que ha definido, no si se utiliza una referencia de clase de base ... por otro lado, los métodos virtuales, que son anulados va a terminar con la versión correcta método se llama, incluso cuando llama usando la referencia de la clase base en una clase de niño.
Por ejemplo, considere estas clases:
public class BaseClass
{
public virtual void Method1() //Virtual method
{
Console.WriteLine("Running BaseClass Method1");
}
public void Method2() //Not a virtual method
{
Console.WriteLine("Running BaseClass Method2");
}
}
public class InheritedClass : BaseClass
{
public override void Method1() //Overriding the base virtual method.
{
Console.WriteLine("Running InheritedClass Method1");
}
public new void Method2() //Can't override the base method; must 'new' it.
{
Console.WriteLine("Running InheritedClass Method2");
}
}
llamada de Let como este, con una instancia de InheritedClass, en una referencia a juego:
InheritedClass inherited = new InheritedClass();
inherited.Method1();
inherited.Method2();
Esto devuelve lo que debe esperar; ambos métodos dicen que se están ejecutando las versiones InheritedClass.
Running InheritedClass Método1
Correr InheritedClass Método2
Este código crea una instancia de la misma, InheritedClass, pero lo almacena en una referencia BaseClass:
BaseClass baseRef = new InheritedClass();
baseRef.Method1();
baseRef.Method2();
Normalmente, bajo los principios de programación orientada a objetos, que debe esperar el mismo resultado que el ejemplo anterior. Pero no obtiene el mismo resultado:
Running InheritedClass Método1
Correr BaseClass Método2
Cuando escribió el código InheritedClass, que puede haber querido todas las llamadas a Method2()
para ejecutar el código que escribió en ella. Normalmente, esto sería cómo funciona - suponiendo que se está trabajando con un método virtual
que ha anulado. Pero debido a que está utilizando un método new
/ oculta, llama a la versión de la referencia que está utilizando, en su lugar.
Si ese es el comportamiento que realmente quieren y, a continuación; Hay que ir. Pero me gustaría sugerir fuertemente que si eso es lo que quiere, puede haber un problema de arquitectura más grande con el código.
Método primordial es override simpley una implementación por defecto de un método de la clase base en la clase derivada.
Método de ocultación: Se puede hacer uso de la 'nueva' palabra clave antes de un método virtual en una clase derivada
como
class Foo
{
public virtual void foo1()
{
}
}
class Bar:Foo
{
public new virtual void foo1()
{
}
}
Ahora si haces otra clase Bar1 que se deriva de barra, puede anular foo1 que es defind en Bar.