c# - utilizar - ¿Debo marcar todos los métodos como virtuales?
metodos virtuales c# (6)
En C #, debe marcar el método como virtual para que sea posible anular. ¿Significa que en C # debe marcar todos los métodos como virtuales (excepto unos pocos que no desea anular), ya que es muy probable que no sepa en qué forma se puede heredar su clase?
No. Si los diseñadores de idiomas pensaban que virtual debería haber sido el predeterminado, entonces habría sido el predeterminado .
Overridablility es una característica y, como todas las características, tiene un costo . Los costos de un método anulable son considerables: hay grandes costos de diseño, implementación y prueba, particularmente si hay alguna "sensibilidad" a la clase; los métodos virtuales son formas de introducir código de terceros no probado en un sistema y eso tiene un impacto en la seguridad.
Si no sabe cómo pretende que su clase sea heredada , no publique su clase porque aún no ha terminado de diseñarla. Su modelo de extensibilidad es definitivamente algo que debe saber con anticipación; debe influir profundamente en su estrategia de diseño y prueba.
Defiendo que todas las clases sean selladas y que todos los métodos no sean virtuales hasta que tenga una razón real enfocada en el cliente para desbloquear o hacer que un método sea virtual.
Básicamente, su pregunta es "No sé cómo mis clientes pretenden consumir mi clase, ¿debería hacerlo extensible arbitrariamente?" No; ¡debes convertirte en conocedor ! Usted no preguntaría "No sé cómo mis clientes van a usar mi clase, entonces ¿debería hacer todas mis propiedades de lectura y escritura? ¿Y debería hacer todos mis métodos de lectura? Escribir propiedades de tipo delegado para que mis usuarios puede reemplazar cualquier método con su propia implementación? " No, no hagas ninguna de esas cosas hasta que tengas evidencia de que un usuario realmente necesita esa capacidad. Dedique su valioso tiempo a diseñar, probar e implementar las funciones que los usuarios realmente desean y necesitan, y hacerlo desde una posición de conocimiento.
En Java, puede marcar el método como definitivo para que sea imposible anularlo.
En C #, debe marcar el método como virtual para que sea posible anular.
¿Significa que en C # debe marcar todos los métodos como virtuales (excepto unos pocos que no desea anular), ya que es muy probable que no sepa en qué forma se puede heredar su clase?
¡No! Como no sabes cómo se heredará tu clase, solo debes marcar un método como virtual
si sabes que quieres que se anule.
En mi opinión, la answer actualmente aceptada es innecesariamente dogmática.
El hecho es que cuando no marca un método como virtual
, otros no pueden anular su comportamiento y cuando marca una clase como sealed
otros no pueden heredar de la clase. Esto puede causar un dolor considerable. No sé cuántas veces maldije una API para marcar las clases sealed
o no marcando los métodos virtual
simplemente porque no anticiparon mi caso de uso.
Teóricamente, podría ser el enfoque correcto para permitir solo los métodos generales y las clases heredadas que se pretenden anular y heredar, pero en la práctica es imposible prever todos los escenarios posibles y realmente no hay una buena razón para estar tan cerca.
- Si no tiene una muy buena razón, entonces no marque las clases como
sealed
. - Si tu biblioteca está destinada a ser consumida por otros, al menos trata de marcar los métodos principales de una clase que contenga el comportamiento como
virtual
.
Una forma de hacer la llamada es mirar el nombre del método o la propiedad. Un método GetLength () en una lista hace exactamente lo que su nombre implica y no permite mucha interpretación . Cambiar su implementación probablemente no sea muy transparente, por lo que marcarlo como virtual
probablemente sea innecesario. Marcar el método Add
como virtual es mucho más útil ya que alguien podría crear una Lista especial que solo acepta algunos objetos a través del método Agregar, etc. Otro ejemplo son los controles personalizados. Querrá que el método de dibujo principal sea virtual
para que otros puedan usar la mayor parte del comportamiento y simplemente cambiar el aspecto, pero es probable que no anule las propiedades X e Y.
Al final, a menudo no tiene que tomar esa decisión de inmediato. En un proyecto interno donde puedes cambiar fácilmente el código de todos modos, no me preocuparía por estas cosas. Si un método necesita ser anulado, siempre puede hacerlo virtual cuando esto sucede. Por el contrario, si el proyecto es una API o una biblioteca que es consumida por otros y lenta para actualizar, ciertamente vale la pena pensar qué clases y métodos pueden ser útiles. En este caso, creo que es mejor ser abierto que estrictamente cerrado.
Hacer que un método sea virtual en general ralentizará cualquier código que necesite llamarlo. Esta ralentización será insignificante, pero en algunos casos puede ser bastante grande (entre otras cosas, porque las llamadas a métodos no virtuales pueden estar alineadas, lo que a su vez puede permitir que el optimizador elimine operaciones innecesarias). No siempre es posible predecir en qué medida las llamadas virtuales pueden afectar la velocidad de ejecución, y en general uno debe dejar de hacer cosas que harán que el código sea más lento, excepto cuando haya un beneficio discernible para hacerlo.
El beneficio de rendimiento de hacer que los métodos no sean virtuales es suficiente en muchos casos para justificar que los métodos sean no virtuales por defecto, pero cuando las clases están diseñadas para ser heredadas, la mayoría de los métodos deben ser virtuales y no ser sellados; el uso principal para métodos no virtuales o sellados debe ser como envoltorios para otros métodos virtuales (posiblemente protegidos) (el código que desea cambiar el comportamiento subyacente debe anular el virtual apropiado en lugar del envoltorio).
Frecuentemente hay razones no relacionadas con el rendimiento para marcar las clases como sealed
o limitar la herencia a otras clases dentro de la asamblea. Entre otras cosas, si una clase es externamente heredable, todos los miembros con ámbito protected
se agregan efectivamente a su API pública, y cualquier cambio en su comportamiento en la clase base puede romper cualquier clase derivada que dependa de ese comportamiento. Por otro lado, si una clase es heredable, hacer que sus métodos sean virtual
realmente no aumenta su exposición. En todo caso, puede reducir la dependencia de la clase derivada de las partes internas de la clase base permitiéndoles "enterrar" por completo los aspectos de la implementación de la clase base que ya no son relevantes en la clase derivada [por ejemplo, si los miembros de List<T>
fueran virtuales, una clase derivada que los anulara a todos podría usar una matriz de matrices para contener cosas (evitando problemas de gran cantidad de objetos), y no tendría que intentar mantener la matriz privada utilizada por la List<T>
consistente con la matriz-de -arrays
No. Solo los métodos que desea que las clases derivadas especifiquen deben ser virtuales.
Virtual no está relacionado con el final.
Para evitar la anulación de un método virtual en c #, usa sealed
public class MyClass
{
public sealed override void MyFinalMethod() {...}
}
Podemos evocar motivos para / de nuevo en cualquiera de los campamentos, pero eso es completamente inútil.
En Java hay millones de métodos públicos no finales no intencionados, pero escuchamos muy pocas historias de terror.
En C # hay millones de métodos públicos sellados, y escuchamos muy pocas historias de terror.
Entonces, no es gran cosa: la necesidad de anular un método público es rara, por lo que es discutible de cualquier manera.
Esto me recuerda otro argumento: si una variable local debería ser final por defecto. Es una muy buena idea, pero no podemos exagerar lo valioso que es. Hay miles de millones de variables locales que podrían ser, pero no lo son, definitivas, pero se ha demostrado que es un problema real.