polimorfico - metodos y funciones en c#
Reemplazando los métodos de extensión (9)
En general, no debe proporcionar la funcionalidad "base" a través de métodos de extensión. Solo deben usarse para "extender" la funcionalidad de la clase. Si tiene acceso al código de clase base, y la funcionalidad que está tratando de implementar es lógicamente parte de la jerarquía de herencia, entonces debe ponerlo en la clase abstracta.
Mi punto es que solo porque puedes no significa que deberías . A menudo es mejor seguir con un buen OOP anticuado y usar las características del lenguaje más nuevo cuando la programación anterior de OO no es suficiente para proporcionarle una solución razonable.
He estado pensando en usar métodos de extensión como reemplazo de una clase base abstracta. Los métodos de extensión pueden proporcionar funcionalidad predeterminada, y pueden "anularse" al poner un método de la misma firma en una clase derivada.
¿Alguna razón por la que no debería hacer esto?
Además, si tengo dos métodos de extensión con la misma firma, ¿cuál se usa? ¿Hay alguna forma de establecer prioridad?
Esta es definitivamente una mala idea. Los métodos de extensión están vinculados estáticamente, lo que significa que, a menos que invoque la anulación de un objeto cuyo tipo de tiempo de compilación es el subtipo, seguirá llamando al método de extensión. Bye-bye polimorfismo. Esta página contiene una buena discusión sobre los peligros de los métodos de extensión.
Hay muchas razones por las que no deberías hacerlo. El primero de ellos es que no puede garantizar cómo se llamarán sus extensiones:
MyExtensions.AMethod(myObj)
o
myObj.AMethod()
El segundo es simplemente azúcar sintáctica para el primero.
Lo que sugieres va en contra del espíritu de la función de idioma. Los métodos de extensión definitivamente no están orientados a objetos. Sin embargo, estás tratando de lograr una técnica orientada a objetos. No use métodos de extensión para eso.
Son operaciones semánticamente diferentes. Por ejemplo, el polimorfismo puede no funcionar de la forma en que lo haría con una clase base abstracta.
Como regla general, use cualquier herramienta de lenguaje para lo que está diseñado. Los métodos de extensión no reemplazan la herencia, son una técnica para extender la funcionalidad de una clase utilizando (normalmente) su interfaz ya visible.
Todas las respuestas aquí indicaron "no se puede", lo cual es cierto hasta donde llega. La mayoría agregó "y no deberías". Me gustaría argumentar que usted debería poder: una pequeña comodidad ya que puede ser.
Tome un doloroso ejemplo del mundo real: si tiene la mala suerte de estar utilizando el nuevo marco MVC, y su código de vista está usando algún método de extensión HtmlHelper por todas partes, y desea anular su comportamiento predeterminado ... ¿entonces qué?
Eres SOL, eso es qué. Incluso si realizó la "OOP thing" - derivada de HtmlHelper, cambie su clase de vista base para reemplazar la instancia de objeto ''Html'' con una instancia de DerivedHtmlHelper, y defina un método ''Foo'' explícito en ella, incluso si lo hizo todo que, al llamar a ''Html.Foo'', se invocará el método de extensión original y no el método.
¡Esto es sorprendente! ¡Después de todo, solo se espera aplicar los métodos de extensión si el objeto aún no tiene un método! ¿Que está pasando aqui?
Bueno, esto porque los métodos de extensión son una característica estática . Es decir, al ver ''Html.Foo'', el compilador observa el tipo estático de ''Html''. Si tiene un método ''Foo'', se llama como de costumbre. De lo contrario, si hay ''SomeClass'' que proporciona un método de extensión ''Foo'', convierte la expresión a ''SomeClass.Foo (Html)''.
Lo que esperaría es que el compilador considere el tipo dinámico del objeto. Es decir, que el código generado (pseudo-) leería ''Html.HasMethod ('' Foo '')? Html.Foo (): SomeClass.Foo (Html) ''.
Esto, por supuesto, incurriría en el costo de usar la reflexión en cada llamada al método de extensión. Por lo tanto, es de esperar que pueda escribir algo como ''Foo vacío estático ( virtual este HtmlHelper html)'' para solicitar explícitamente al compilador que inserte la verificación en tiempo de ejecución. Llamar a esto un "método de extensión virtual".
Sin embargo, en su presupuesto limitado y su sabiduría infinita, los diseñadores del lenguaje C # fueron con la alternativa más eficiente y restringida. Lo que me deja SOL aún cuando necesito anular el comportamiento predeterminado de HtmlHelper :-(
En primer lugar, sería bueno comprobar [nuevo] como un modificador de método: debería proporcionar la misma separación de perf y método, pero con una incomodidad mucho menor.
Si después de eso todavía estás considerando los mismos trucos, estas son las principales opciones a tener en cuenta: no se necesita ideología, solo se enumeran los aspectos que deberás conocer :-)
Para empezar, deberá limitar todos los usos a los parámetros de función con plantilla para garantizar la selección determinística de funciones, ya que este truco creará la situación que es exactamente inversa a la que CLR garantiza la prioridad de enlace determinística entre los límites de llamada de función.
Si todavía va a tener una clase base abstracta y posee todo el código, simplemente "convertir" un método base en extensión no le comprará nada y le costará la pérdida de una interfaz común que seguirá existiendo para todo lo demás. , incluido el costo de vtables.
Si pretende convertir clases abstractas en concretas, eliminando todos los métodos virtuales por razones de rendimiento y utilizando clases base concretas y todos los derivados exclusivamente en plantillas (incluso puede que se conviertan en estructuras), entonces ese truco podría comprarle algo de rendimiento. Solo debe tener en cuenta que no podrá volver al uso basado en interfaz sin refactorizar. También deberá comprobar el orden de invocación en funciones que no sean de plantilla con la clase base en la firma y tener mucho cuidado si tiene varias DLL-S. Pruebe lo mismo con el operador [nuevo] y vea si funciona mejor.
Además, tendrá que escribir la implementación de métodos por separado para cada clase derivada, incluso si tienen exactamente la misma funcionalidad, por lo que si tiene muchas clases derivadas está buscando mucha duplicación de código. Esta parte te afectará incluso si usas [nuevo] a menos que vuelvas a los métodos virtuales e introduzcas otra capa en la herencia, lo que cancelará todas las ganancias de rendimiento, por supuesto.
Estoy de acuerdo con Michael. Las clases base deben contener toda la funcionalidad básica. Los métodos de extensión deberían, obviamente, extender la funcionalidad básica. En los lenguajes dinámicos como Ruby, a menudo es típico usar métodos de extensión para proporcionar funcionalidad adicional en lugar de usar subclases. Básicamente, los métodos de extensión están ahí para reemplazar el uso de subclases, no para reemplazar el uso de clases base.
La única excepción a esto que he visto es que si tienes múltiples tipos que tienen jerarquías de clases diferentes (como controles de winform), puedes crear una subclase de cada una que implementen e interfieran y luego extender esa interfaz, dando así "base" funcionalidad a un grupo de controles diferentes, sin extender todo como Control u Objeto.
Editar: respondiendo tu segunda pregunta
Creo que el compilador captará esto por ti.
Es posible que desee considerar el polimorfismo anterior si no necesita clases derivadas únicas.
Algunas pautas generales de este artículo de MSDN:
Una vez que se define un método dentro de una clase, ya no se ejecutará ningún método de extensión para esa clase que comparta ese nombre de método.
Los métodos de extensión se cargan por espacio de nombres. Para permitirle al usuario otros métodos de extensión, probablemente debería evitar poner los métodos de extensión en el mismo espacio de nombres que la clase que se está ampliando.
Si varios ensamblados dependientes están consumiendo la misma biblioteca, cada uno de los cuales requiere una función personalizada contra una clase en la biblioteca, puede declarar la extensión específica para el ensamblado dependiente en un espacio de nombre dentro de ese ensamblaje. Otros ensamblajes que no dependen de ese ensamblaje no tendrán esa extensión.
Si bien esto no es polimorfismo, es posible que no desee utilizar el polimorfismo, ya que se requerirían todas las clases derivadas para implementar sus reemplazos.
En otras palabras, si tiene derivadas con lógica variante específica, use polimorfismo. Si simplemente necesita funciones personalizadas en casos específicos que de otro modo podrían ser confusos o gravosos, los métodos de extensión no son una mala idea.
Además, vea la respuesta de JoshRivers que muestra cómo anular un método de extensión utilizando un espacio de nombres dentro de una clase dentro de un espacio de nombres separado.
Agregar un enlace a otra pregunta de SO que tenga una respuesta alternativa a "No se puede". Más ''no se puede ... a menos que''.