Estaba mirando esta publicación de blog y tenía las siguientes preguntas:
- ¿Por qué necesitamos la
new
palabra clave? ¿Es solo para especificar que se está ocultando un método de clase base? Quiero decir, ¿por qué lo necesitamos? Si no usamos laoverride
palabra clave, ¿no estamos ocultando el método de la clase base? - ¿Por qué el valor predeterminado en C # es ocultar y no anular? ¿Por qué los diseñadores lo implementaron de esta manera?
c#
overriding
Salvadera
fuente
fuente
Respuestas:
Buena pregunta. Permítanme reformularlos.
Déjame responder esa pregunta con un ejemplo. Tiene una interfaz de CLR v1:
interface IEnumerable { IEnumerator GetEnumerator(); }
Súper. Ahora, en CLR v2 tienes genéricos y piensas "hombre, si solo hubiéramos tenido genéricos en v1, habría hecho de esta una interfaz genérica. Pero no lo hice. Debería hacer algo compatible con él ahora que sea genérico para que Obtengo los beneficios de los genéricos sin perder la compatibilidad con versiones anteriores del código que espera IEnumerable ".
interface IEnumerable<T> : IEnumerable { IEnumerator<T> .... uh oh
¿De qué vas a llamar al método GetEnumerator
IEnumerable<T>
? Recuerde, desea que oculte GetEnumerator en la interfaz base no genérica. Usted no quiere que lo que se llamará a menos que esté explícitamente en una situación revés-comp.Eso solo justifica el método de ocultación. Para obtener más ideas sobre las justificaciones del método de ocultación, consulte mi artículo sobre el tema .
Porque queremos advertirle que está ocultando algo y podría estar haciéndolo accidentalmente. Recuerde, es posible que esté ocultando algo accidentalmente debido a una edición de la clase base realizada por otra persona, en lugar de por usted editando su clase derivada.
Misma razón. Es posible que esté ocultando algo accidentalmente porque acaba de adquirir una nueva versión de una clase base. Esto sucede todo el tiempo. FooCorp crea una clase base B. BarCorp crea una clase D derivada con un método Bar, porque a sus clientes les gusta ese método. FooCorp ve eso y dice bueno, es una buena idea, podemos poner esa funcionalidad en la clase base. Lo hacen y envían una nueva versión de Foo.DLL, y cuando BarCorp adquiere la nueva versión, sería bueno que se les dijera que su método ahora oculta el método de la clase base.
Queremos que esa situación sea una advertencia y no un error porque convertirlo en un error significa que esta es otra forma del problema de la clase base frágil . C # se ha diseñado cuidadosamente para que cuando alguien realiza un cambio en una clase base, se minimizan los efectos en el código que usa una clase derivada.
Porque la anulación virtual es peligrosa . La anulación virtual permite que las clases derivadas cambien el comportamiento del código compilado para usar clases base. Hacer algo peligroso, como anular, debe ser algo que haga consciente y deliberadamente , no por accidente.
fuente
Si el método en la clase derivada está precedido por la nueva palabra clave, el método se define como independiente del método en la clase base.
Sin embargo, si no especifica new o overrides, la salida resultante es la misma que si hubiera especificado new, pero recibirá una advertencia del compilador (ya que es posible que no sepa que está ocultando un método en el método de la clase base, o, de hecho, es posible que haya querido anularlo y simplemente se olvidó de incluir la palabra clave).
Por lo tanto, le ayuda a evitar errores y a mostrar explícitamente lo que quiere hacer y hace que el código sea más legible, por lo que uno puede entenderlo fácilmente.
fuente
Vale la pena señalar que el único efecto de
new
en este contexto es suprimir una Advertencia. No hay cambio de semántica.Entonces, una respuesta es: debemos
new
indicarle al compilador que la ocultación es intencional y eliminar la advertencia.La pregunta de seguimiento es: si no puede o no puede anular un método, ¿por qué introduciría otro método con el mismo nombre? Porque esconderse es en esencia un conflicto de nombres. Y, por supuesto, lo evitaría en la mayoría de los casos.
La única buena razón que se me ocurre para la ocultación intencional es cuando una interfaz te impone un nombre.
fuente
En C #, los miembros están sellados de forma predeterminada, lo que significa que no puede anularlos (a menos que estén marcados con las palabras clave
virtual
oabstract
) y esto por razones de rendimiento . El nuevo modificador se usa para ocultar explícitamente un miembro heredado.fuente
Si la anulación era predeterminada sin especificar la
override
palabra clave, podría anular accidentalmente algún método de su base solo debido a la igualdad de nombres.La estrategia del compilador .Net es emitir advertencias si algo podría salir mal, solo para estar seguro, por lo que, en este caso, si la anulación fuera la predeterminada, debería haber una advertencia para cada método anulado, algo como 'advertencia: verifique si realmente quiere para anular'.
fuente
Mi conjetura se debe principalmente a la herencia de múltiples interfaces. Usando interfaces discretas, sería muy posible que dos interfaces distintas usen la misma firma de método. Permitir el uso de la
new
palabra clave le permitiría crear estas diferentes implementaciones con una clase, en lugar de tener que crear dos clases distintas.Actualizado ... Eric me dio una idea sobre cómo mejorar este ejemplo.
public interface IAction1 { int DoWork(); } public interface IAction2 { string DoWork(); } public class MyBase : IAction1 { public int DoWork() { return 0; } } public class MyClass : MyBase, IAction2 { public new string DoWork() { return "Hi"; } } class Program { static void Main(string[] args) { var myClass = new MyClass(); var ret0 = myClass.DoWork(); //Hi var ret1 = ((IAction1)myClass).DoWork(); //0 var ret2 = ((IAction2)myClass).DoWork(); //Hi var ret3 = ((MyBase)myClass).DoWork(); //0 var ret4 = ((MyClass)myClass).DoWork(); //Hi } }
fuente
new
palabra clave le permite también cambiar la base de herencia para todos los hijos de ese punto.Como se señaló, la ocultación de método / propiedad hace posible cambiar cosas sobre un método o propiedad que no podrían cambiarse fácilmente de otra manera. Una situación en la que esto puede ser útil es permitir que una clase heredada tenga propiedades de lectura y escritura que son de solo lectura en la clase base. Por ejemplo, suponga que una clase base tiene un grupo de propiedades de solo lectura llamadas Value1-Value40 (por supuesto, una clase real usaría mejores nombres). Un descendiente sellado de esta clase tiene un constructor que toma un objeto de la clase base y copia los valores de allí; la clase no permite que se cambien después de eso. Un descendiente diferente, heredable, declara una propiedad de lectura-escritura llamada Value1-Value40 que, cuando se lee, se comporta igual que las versiones de la clase base pero, cuando se escribe, permite que se escriban los valores.
Una molestia con este enfoque, tal vez alguien pueda ayudarme, es que no conozco una forma de sombrear y anular una propiedad en particular dentro de la misma clase. ¿Alguno de los lenguajes CLR lo permite (yo uso vb 2005)? Sería útil si el objeto de la clase base y sus propiedades pudieran ser abstractos, pero eso requeriría que una clase intermedia anulara las propiedades Value1 a Value40 antes de que una clase descendiente pudiera sombrearlas.
fuente