language - object oriented concepts c#
Es el método que oculta siempre una buena idea (8)
En C #, el new
modificador se puede utilizar para ocultar un método de clase base sin anular el método de clase base.
Nunca me he encontrado con una situación donde esconder un método fuera la mejor opción disponible. ¿Hay alguna situación donde la ocultación de métodos es la mejor opción?
A menudo es una buena opción cuando está creando controles personalizados, y quiere evitar que ciertas propiedades aparezcan en el diseñador. Algunas veces las propiedades no son reemplazables, pero al diseñador no le importa eso, solo le importa si la propiedad pública de nivel más bajo tiene o no el atributo [Browsable]
.
Por ejemplo, supongamos que su control no admite el relleno. La propiedad Control.Padding no es reemplazable. Pero también sabe que nada malo va a pasar si alguien establece el relleno, es solo que la propiedad no hace nada, por lo que no quiere que sus usuarios lo vean en el diseñador y piensen que realmente funciona. Entonces, escóndelo
public class MyControl : Control
{
[Browsable(false)]
public new Padding Padding
{
get { return base.Padding; }
set { base.Padding = value; }
}
}
En este caso, estamos literalmente usando el miembro que se esconde para ocultar el miembro , del diseñador.
Como un aparte, soy consciente de que hay otros medios para lograr este objetivo: esta es solo una opción posible.
El ejemplo más común que puedo pensar aquí es cosas como DbCommand
vs SqlCommand
; los tipos de hormigón ( SqlCommand
etc.) generalmente ocultan muchos métodos para que los tipos de retorno de propiedades / métodos muestren el tipo de implementación correcto. Esto se debe a que los propios objetos relacionados tienen características adicionales (específicas de la implementación), y la persona que llama no quiere tener que emitir cada vez que llaman para hacer algo.
Existen razones raras, pero muy buenas, para usar el método de ocultar. Eric Lippert publicó un gran ejemplo en su blog:
interface IEnumerable<T> : IEnumerable {
new IEnumerator<T> GetEnumerator();
}
Sin embargo, creo que esconderse debería ser la excepción, y solo usado con moderación.
Recientemente tuve un caso donde la palabra clave ''nueva'' fue bastante útil. Estaba escribiendo pruebas unitarias para los métodos en una base de código heredada y algunos de los métodos en las clases que estaba escribiendo pruebas tenían dependencias externas ocultas dentro de los métodos. Incluir un marco burlón para resolver el problema parecía innecesario en ese momento, así que, en lugar de utilizar un marco burlón, heredé la clase que quería probar dentro de la clase de prueba de la unidad. Sin embargo, el método principal no era virtual, por lo que no se pudo anular. Mi primera solución fue simplemente agregar la palabra clave virtual al método original para permitir que se anule y las pruebas funcionen de maravilla. Aunque funcionó, no creo que agregar palabras clave virtuales a las firmas de métodos solo por la necesidad de "simularlo" en una prueba unitaria sea una buena decisión de diseño (pero podría estar equivocado). En cambio, el uso de la palabra clave ''nueva'' en la clase hija me permitió ''deshacerme'' de las dependencias de métodos padres ocultando el método original con un método con valores de retorno estáticos, escribiendo pruebas de unidades rápidas para el resto de los métodos también. como cuando se cambian métodos no virtuales a métodos virtuales.
En general, no estoy seguro de que esta técnica pueda considerarse una buena práctica. Sin embargo, el uso de este tipo de técnica puede ser muy útil al escribir un banco de pruebas para facilitar la refactorización cuando se trabaja con código heredado con muchas dependencias y no tiene un conjunto de pruebas automatizado para empezar. Es muy probable que las pruebas mejoren cuando se complete el trabajo de refactorización.
EDITAR: Debido a que el ocultamiento de métodos solo ocurre en la clase privada heredada, no debería causar confusión alguna en otros casos de uso.
Sí, si usted es, por ejemplo, solo un consumidor de una clase base y se publica una nueva versión de la clase base que de repente tiene el método con la misma firma exacta que uno de los métodos que ya implementó en su derivado clase, necesitas poder ocultar el método de la clase base y usar new
para dejar en claro que estás ocultando el método de la clase base ...
Tiendo a usarlo a veces para conveniencia de los que llaman, algo así como:
abstract public class Animal { }
public class Mouse : Animal { }
public class AnimalTrap
{
public Animal TrappedAnimal { get; }
}
public class MouseTrap : AnimalTrap
{
new public Mouse TrappedAnimal
{
get { return (Mouse)base.TrappedAnimal; }
}
}
Por lo tanto, la persona que llama no tiene que transmitir el contenido al Mouse
cuando la clase derivada garantiza que el animal atrapado siempre será un mouse. Y la funcionalidad polimórfica permanece intacta.
Tuve que recurrir al método de ocultar una vez. Estaba usando una biblioteca de terceros que proporcionaba un método que no era virtual (esa es la clave de todo). Fue un método que asignó una instancia de algo. Pero necesitaba ampliar la funcionalidad de ese método.
Así que utilicé la palabra clave ''nueva'' para ocultar la implementación de la clase base y proporcionar la mía en una clase derivada. Cómo eso no significa que no llamé al método de la clase base. De hecho, sí llamé al método de la clase base, pero también hice otras cosas en mi método, y al final todo salió bien.
Entonces diría que las razones serían las siguientes:
- Una clase base está en una biblioteca de terceros sobre la que no tienes control.
- Una clase base tiene un método no virtual que debe sobrescribir.
- Siempre preste especial atención a extender la funcionalidad y no a reemplazarla.
- Y siempre use esto como último recurso cuando esté atorado ... :)
Mis 2 centavos ...
Una vez que lo he usado está en un control de winforms personalizado. Mi control personalizado anula la propiedad Text
, y quiero plantear un evento cada vez que cambie. La clase base de Control
viene con un evento TextChanged
, sin embargo, el evento base tiene atributos abofeteados para evitar que aparezca en el diseñador o en intellisense. Dado que estamos utilizando el evento en nuestro control personalizado, esto no es deseable, por lo que hacemos lo siguiente:
[Browsable(true)]
[EditorBrowsable(EditorBrowsableState.Always)]
public new event EventHandler TextChanged
{
add { base.TextChanged += value; }
remove { base.TextChanged -= value; }
}
Los controladores de eventos seguirán agregándose al mismo evento, independientemente del tipo de referencia que se use para acceder a él, pero las referencias de tipo derivado mostrarán el evento TextChanged
en intellisense, y cuando nuestro control se coloque en un formulario en el diseñador, el evento TextChanged
se mostrará en la ventana de propiedades.