sobreescribir - override vs overload c#
¿Es posible anular un método no virtual? (7)
¿Hay alguna manera de anular un método no virtual? o algo que da resultados similares (aparte de crear un nuevo método para llamar al método deseado)?
Me gustaría sobrescribir un método de Microsoft.Xna.Framework.Graphics.GraphicsDevice
con pruebas de unidades en mente.
¿Hay alguna manera de anular un método no virtual? o algo que da resultados similares (aparte de crear un nuevo método para llamar al método deseado)?
No puede anular un método no virtual. Sin embargo, puede usar la new
palabra clave modificador para obtener resultados similares:
class Class0
{
public int Test()
{
return 0;
}
}
class Class1 : Class0
{
public new int Test()
{
return 1;
}
}
. . .
// result of 1
Console.WriteLine(new Class1().Test());
También querrás asegurarte de que el modificador de acceso también sea el mismo, de lo contrario no obtendrás la herencia por la línea. Si otra clase hereda de la Class1
la new
palabra clave en la Class1
no afectará a los objetos heredados de ella, a menos que el modificador de acceso sea el mismo.
Si el modificador de acceso no es el mismo:
class Class0
{
protected int Test()
{
return 0;
}
}
class Class1 : Class0
{
// different access modifier
new int Test()
{
return 1;
}
}
class Class2 : Class1
{
public int Result()
{
return Test();
}
}
. . .
// result of 0
Console.WriteLine(new Class2().Result());
... versus si el modificador de acceso es el mismo:
class Class0
{
protected int Test()
{
return 0;
}
}
class Class1 : Class0
{
// same access modifier
protected new int Test()
{
return 1;
}
}
class Class2 : Class1
{
public int Result()
{
return Test();
}
}
. . .
// result of 1
Console.WriteLine(new Class2().Result());
Como se señaló en una respuesta anterior, este no es un buen principio de diseño.
Creo que está sobrecargando y sobreescribiendo confundido, sobrecarga significa que tiene dos o más métodos con el mismo nombre pero diferentes conjuntos de parámetros mientras que sobrescribir significa que tiene una implementación diferente para un método en una clase derivada (reemplazando o modificando el comportamiento) en su clase base).
Si un método es virtual, puede anularlo utilizando la palabra clave override en la clase derivada. Sin embargo, los métodos no virtuales solo pueden ocultar la implementación base al usar la palabra clave nueva en lugar de la palabra clave de anulación. La ruta no virtual es inútil si la persona que llama accede al método a través de una variable escrita como el tipo de base, ya que el compilador usaría un envío estático al método base (lo que significa que el código en su clase derivada nunca sería llamado).
Nunca hay nada que le impida agregar una sobrecarga a una clase existente, pero solo el código que sabe sobre su clase podría acceder a ella.
En el caso de que esté heredando de una clase no derivada, podría simplemente crear una superclase abstracta y heredarla de la cadena descendente.
Hay una forma de lograr esto utilizando la clase abstracta y el método abstracto.
Considerar
Class Base
{
void MethodToBeTested()
{
...
}
void Method1()
{
}
void Method2()
{
}
...
}
Ahora, si deseas tener diferentes versiones del método MethodToBeTested (), entonces cambia Class Base a una clase abstracta y el método MethodToBeTested () como un método abstracto
abstract Class Base
{
abstract void MethodToBeTested();
void Method1()
{
}
void Method2()
{
}
...
}
Con abstract void MethodToBeTested () viene un problema; la implementación se ha ido.
Por lo tanto, cree una class DefaultBaseImplementation : Base
para tener la implementación predeterminada.
Y crea otra class UnitTestImplementation : Base
para tener la implementación de la prueba unitaria.
Con estas 2 nuevas clases, la funcionalidad de la clase base puede ser anulada.
Class DefaultBaseImplementation : Base
{
override void MethodToBeTested()
{
//Base (default) implementation goes here
}
}
Class UnitTestImplementation : Base
{
override void MethodToBeTested()
{
//Unit test implementation goes here
}
}
Ahora tiene 2 clases implementando (anulando) MethodToBeTested()
.
Puede instanciar la clase (derivada) según sea necesario (es decir, ya sea con implementación base o con implementación de prueba unitaria).
No, no puedes anular un método no virtual. Lo más cercano que puede hacer es ocultar el método creando un new
método con el mismo nombre, pero esto no es aconsejable ya que rompe los buenos principios de diseño.
Pero incluso ocultar un método no le dará tiempo de ejecución, el envío polimórfico de llamadas a métodos como haría una verdadera llamada a un método virtual. Considera este ejemplo:
using System;
class Example
{
static void Main()
{
Foo f = new Foo();
f.M();
Foo b = new Bar();
b.M();
}
}
class Foo
{
public void M()
{
Console.WriteLine("Foo.M");
}
}
class Bar : Foo
{
public new void M()
{
Console.WriteLine("Bar.M");
}
}
En este ejemplo, ambas llamadas al método M
imprimen Foo.M
Como puede ver, este enfoque le permite tener una nueva implementación para un método, siempre que la referencia a ese objeto sea del tipo derivado correcto, pero si se oculta un método base se rompe el polimorfismo.
Le recomendaría que no oculte los métodos básicos de esta manera.
Tiendo a lado con aquellos que favorecen el comportamiento predeterminado de C # que los métodos no son virtuales por defecto (a diferencia de Java). Yo iría más allá y diría que las clases también deberían estar selladas por defecto. La herencia es difícil de diseñar correctamente y el hecho de que haya un método que no está marcado como virtual indica que el autor de ese método nunca tuvo la intención de anular el método.
Editar: "despacho polimórfico del tiempo de ejecución" :
Lo que quiero decir con esto es el comportamiento predeterminado que ocurre en el momento de la ejecución cuando llama a métodos virtuales. Digamos, por ejemplo, que en mi ejemplo de código anterior, en lugar de definir un método no virtual, de hecho definí un método virtual y un verdadero método reemplazado también.
Si b.Foo
que llamar a b.Foo
en ese caso, el CLR determinaría correctamente el tipo de objeto al que apunta la referencia b
como Bar
y enviaría la llamada a M
apropiada.
No, no puedes.
Solo puede anular un método virtual; consulte el MSDN aquí :
En C #, las clases derivadas pueden contener métodos con el mismo nombre que los métodos de clase base.
- El método de clase base debe definirse virtual.
Si la clase base no está sellada, puede heredarla y escribir un nuevo método que oculte la base (use la palabra clave "nueva" en la declaración del método). De lo contrario, no, no puede anularlo porque nunca fue la intención original del autor que se anule, por lo que no es virtual.