C # diseño: ¿Por qué se requiere nueva / anulación de métodos abstractos, pero no en los métodos virtuales?
-
30-09-2019 - |
Pregunta
¿Por qué es nuevo / anulación requerida en los métodos abstractos, pero no en los métodos virtuales?
Muestra 1:
abstract class ShapesClass
{
abstract public int Area(); // abstract!
}
class Square : ShapesClass
{
int x, y;
public int Area() // Error: missing 'override' or 'new'
{
return x * y;
}
}
El compilador mostrará este error: Para hacer que el miembro actual de anulación que la aplicación, añadir la palabra clave override. De lo contrario, añadir la nueva palabra clave
Ejemplo 2:
class ShapesClass
{
virtual public int Area() { return 0; } // it is virtual now!
}
class Square : ShapesClass
{
int x, y;
public int Area() // no explicit 'override' or 'new' required
{
return x * y;
}
}
Esto compilará bien, ocultando el método por defecto.
comprendo perfectamente las diferencias técnicas. Sin embargo, me pregunto por qué el lenguaje fue diseñado de esa manera. ¿No sería mejor tener la misma restricción en la "Muestra 2" también? Es decir, en la mayoría de los casos si se crea un método con el mismo nombre que en la clase padre, que por lo general la intención de anularlo. Así que creo que indica explícitamente Sustituir / Nueva tendría sentido en métodos virtuales también.
¿Hay una razón En cuanto al diseño de este comportamiento?
Actualización: La segunda muestra realmente causa una advertencia. El primer ejemplo muestra un error porque se requiere la subclase para implementar el método abstracto. No vi la advertencia en VS .. hace perfectamente sentido para mí ahora. Gracias.
Solución
El uso de cualquiera de los C # 3.0 compilador como enviado en .NET 3.5 SP1, o el compilador de C # 4.0 como enviado en .NET 4.0, me sale el siguiente error para su primer ejemplo:
error CS0534: 'ConsoleApplication3.Square' no implementa miembro abstracta heredada 'ConsoleApplication3.ShapesClass.Area ()'
Y el siguiente Advertencia para el segundo:
advertencia CS0114: 'ConsoleApplication3.Square.Area ()' cueros miembro heredado 'ConsoleApplication3.ShapesClass.Area ()'. Para hacer que el miembro actual de anulación que la aplicación, añadir la palabra clave override. De lo contrario, añadir la nueva palabra clave.
En el primer caso se trata de un error, ya que no está realmente reemplazando el método de base, lo que significa que no hay aplicación para el método abstracto en una clase concreta. En el segundo caso se trata de una advertencia porque el código es técnicamente correcto, pero el compilador sospecha que no es lo que quería decir. Esta es una de las razones es generalmente una buena idea para que las "advertencias tratan como errores" ajuste de compilación.
Así que no puedo repro su comportamiento, y el comportamiento de las miradas del compilador bien para mí. ¿Qué versión del compilador está usando?
Otros consejos
Aquí está la respuesta directamente de la especificación C #.
... ocultar un nombre de acceso desde una alcance heredado provoca una advertencia para ser informó. En el ejemplo
class Base
{
public void F() {}
}
class Derived: Base
{
public void F() {} // Warning, hiding an inherited name
}
la declaración de F en causas derivados una advertencia que se informa. un escondite nombre heredado no es específicamente una de error, ya que ello impediría evolución separada de clases base. Por ejemplo, el anterior podría situación han surgido porque una tarde versión de Base introdujo un método F que no estaba presente en una anterior versión de la clase. Tenía el anteriormente situación ha sido un error, entonces cualquier cambio realizado en una clase base en una biblioteca de clases versionado por separado potencialmente podría causar derivada clases para ser válidas. La advertencia causada por ocultar un nombre puede heredado ser eliminado a través del uso de la nueva modificador:
class Base
{
public void F() {}
}
class Derived: Base
{
new public void F() {}
}
El nuevo modificador indica que el F en Derivado es “nuevo”, y que es de hecho la intención de ocultar el heredada miembro.
La diferencia es que el método abstracto tiene que ser reemplazado, pero la virtual no lo hace.
Es un error para heredar la clase abstracta (en una clase no abstracta) sin poner en práctica todos los miembros abstractas, sino que sólo te dan una advertencia cuando se hereda de la clase sin especificar override
o new
para el método virtual.
Creo que en la primera forma se obtiene el error de compilación, porque el método abstracto se oculta y no se han aplicado (de modo eficaz su clase está mal, y que sería difícil de averiguar por qué). En el segundo caso se obtiene solamente una advertencia, porque la clase es utilizable.
de versiones
A primera vista, se puede pensar que esconderse método no parece particularmente útil. Hay una situación
donde es posible que necesite usarlo, sin embargo. Digamos que usted desea utilizar una clase llamada MotorVehicle
que
fue escrito por otro programador, y desea utilizar esta clase para derivar su propia clase. Más lejos,
Supongamos también que desea definir un método Accelerate()
en su clase derivada. Por ejemplo:
public class Car : MotorVehicle
{
// define the Accelerate() method
public void Accelerate()
{
Console.WriteLine(“In Car Accelerate() method”);
Console.WriteLine(model + “ accelerating”);
}
}
A continuación, vamos a suponer que el otro programador más adelante modifica la clase y decide MotorVehicle
añadir su propio método virtual Accelerate()
:
public class MotorVehicle
{
// define the Accelerate() method
public virtual void Accelerate()
{
Console.WriteLine(“In MotorVehicle Accelerate() method”);
Console.WriteLine(model + “ accelerating”);
}
}
La adición de este método Accelerate()
por la otra programador causa un problema: La
Método Accelerate()
en sus pieles clase Car
el método heredado Accelerate()
ahora se define en
MotorVehicle
su clase. Más tarde, cuando se llega a compilar su clase Car
, no está claro que el compilador
ya sea que realmente se refiere a su método para ocultar el método heredado. Debido a esto, la
compilador informa de la siguiente advertencia cuando intenta compilar su clase Car:
advertencia CS0114: ‘Car.Accelerate ()’ cueros heredan miembro ‘MotorVehicle.Accelerate ()’. Para hacer que la corriente de anulación miembro de que se aplicación, añadir la palabra clave override. De lo contrario, añadir la nueva palabra clave.