Un "no creyente" de C # me preguntaba cuál era el propósito de los métodos de extensión. Le expliqué que luego podría agregar nuevos métodos a los objetos que ya estaban definidos, especialmente cuando no posee / controla la fuente del objeto original.
Él mencionó "¿Por qué no agregar un método a su propia clase?" Hemos estado dando vueltas y vueltas (en el buen sentido). Mi respuesta general es que es otra herramienta en el cinturón de herramientas, y su respuesta es que es un desperdicio inútil de una herramienta ... pero pensé que obtendría una respuesta más "ilustrada".
¿Cuáles son algunos de los escenarios en los que ha utilizado métodos de extensión que no podría (o no debería) haber utilizado un método agregado a su propia clase?
c#
extension-methods
2 revoluciones
fuente
fuente
Extensions.To(1, 10)
no tiene sentido y1.To(10)
es descriptivo. Por supuesto que entiendo el aspecto técnico del que estás hablando, simplemente diciendo. De hecho, hay escenarios en los que uno " no podría haber" utilizado un enfoque de extensión en lugar de métodos estáticos, la reflexión, por ejemplo, otro caso esdynamic
.Respuestas:
Creo que los métodos de extensión ayudan mucho al escribir código; si agrega métodos de extensión a los tipos básicos, los obtendrá rápidamente en intellisense.
Tengo un proveedor de formato para formatear un tamaño de archivo . Para usarlo necesito escribir:
Console.WriteLine(String.Format(new FileSizeFormatProvider(), "{0:fs}", fileSize));
Creando un método de extensión puedo escribir:
Más limpio y sencillo.
fuente
LongToFileSize(fileSize)
, lo cual es igual de conciso y posiblemente igual de claro.El único ventaja de los métodos de extensión es la legibilidad del código. Eso es.
Los métodos de extensión le permiten hacer esto:
en lugar de esto:
Ahora hay muchas cosas en C # que son así. En otras palabras, hay muchas características en C # que parecen triviales y no tienen un gran beneficio en sí mismas. Sin embargo, una vez que comienzas a combinar estas características, comienzas a ver algo un poco más grande que la suma de sus partes. LINQ se beneficia enormemente de los métodos de extensión, ya que las consultas LINQ serían casi ilegibles sin ellos. LINQ sería posible sin métodos de extensión, pero no es práctico.
Los métodos de extensión se parecen mucho a las clases parciales de C #. Por sí mismos no son muy útiles y parecen triviales. Pero cuando empiezas a trabajar con una clase que necesita código generado, las clases parciales empiezan a tener mucho más sentido.
fuente
¡No olvide las herramientas! Cuando agrega un método de extensión M en el tipo Foo, obtiene 'M' en la lista intellisense de Foo (asumiendo que la clase de extensión está dentro del alcance). Esto hace que 'M' sea mucho más fácil de encontrar que MyClass.M (Foo, ...).
Al final del día, es solo azúcar sintáctico para otros métodos estáticos, pero como comprar una casa: '¡ubicación, ubicación, ubicación!' Si se cuelga del tipo, la gente lo encontrará.
fuente
String
) que vienen con una lista bastante larga de métodos de instancia, por lo que este problema no es específico de los métodos de extensión.Dos beneficios más de los métodos de extensión con los que me he encontrado:
Select(...)
,Where(...)
, etc. Hung fuera de laIEnumerable<T>
interfaz.fuente
Algunos de los mejores usos que tuve para los métodos de extensión es la capacidad de:
sealed
.Tomemos, por ejemplo
IEnumerable<T>
,. Si bien es rico en métodos de extensión, me pareció molesto que no implementara un método ForEach genérico. Entonces, hice el mío:public void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action) { foreach ( var o in enumerable ) { action(o); } }
Voila, todos mis
IEnumerable<T>
objetos independientemente del tipo de implementación, y si lo escribí o no, o si alguien más ahora tenía unForEach
método agregando una declaración de "uso" apropiada en mi código.fuente
Una de las grandes razones para utilizar métodos de extensión es LINQ. Sin métodos de extensión, mucho de lo que puede hacer en LINQ sería muy difícil. Los métodos de extensión Where (), Contains (), Select significan que se agrega mucha más funcionalidad a los tipos existentes sin cambiar su estructura.
fuente
Hay muchas respuestas sobre el ventajas de los métodos de extensión; ¿ Qué tal uno que aborde las desventajas ?
La mayor desventaja es que no hay ningún error o advertencia del compilador si tiene un método regular y un método de extensión con la misma firma en el mismo contexto.
Suponga que crea un método de extensión que se aplica a una clase en particular. Luego, más tarde, alguien crea un método con una firma idéntica en esa clase.
Su código se compilará y es posible que ni siquiera obtenga un error de tiempo de ejecución. Pero ya no está ejecutando el mismo código que antes.
fuente
Interfaces fluidas y sensibilidad al contexto como lo demostró Greg Young en CodeBetter
fuente
Mi argumento personal para los métodos de extensión es que encajan muy bien en un diseño de programación orientada a objetos: considere el método simple
bool empty = String.IsNullOrEmpty (myString)
en comparación con
bool empty = myString.IsNullOrEmpty ();
fuente
Hay un montón de excelentes respuestas arriba sobre lo que los métodos de extensión le permiten hacer.
Mi respuesta corta es: casi eliminan la necesidad de fábricas.
Solo señalaré que no son un concepto nuevo y una de las mayores validaciones de ellos es que son una característica excelente en Objective-C ( categorías ). Añaden tanta flexibilidad al desarrollo basado en marcos que NeXT tenía a los modeladores financieros de la NSA y Wall Street como principales usuarios.
REALbasic también los implementa como métodos extendidos y han sido de uso similar allí simplificando el desarrollo.
fuente
Me gustaría apoyar las otras respuestas aquí que mencionan la legibilidad mejorada del código como una razón importante detrás de los métodos de extensión. Demostraré esto con dos aspectos de esto: encadenamiento de métodos frente a llamadas a métodos anidados y desorden de una consulta LINQ con nombres de clases estáticas sin sentido.
Tomemos esta consulta LINQ como ejemplo:
numbers.Where(x => x > 0).Select(x => -x)
Ambos
Where
ySelect
son métodos de extensión, definidos en la clase estáticaEnumerable
. Por lo tanto, si los métodos de extensión no existieran, y estos fueran métodos estáticos normales, la última línea de código esencialmente tendría que verse así:Enumerable.Select(Enumerable.Where(numbers, x => x > 0), x => -x)
Vea cuánto más desagradable se acaba de hacer esa consulta.
En segundo lugar, si ahora quisiera introducir su propio operador de consulta, naturalmente no tendría forma de definirlo dentro de la
Enumerable
clase estática, como todos los demás operadores de consulta estándar, porqueEnumerable
está en el marco y no tiene control sobre esa clase. Por lo tanto, tendría que definir su propia clase estática que contenga métodos de extensión. A continuación, puede recibir consultas como esta:Enumerable.Select(MyEnumerableExtensions.RemoveNegativeNumbers(numbers), x => -x) // ^^^^^^^^^^^^^^^^^^^^^^ // different class name that has zero informational value // and, as with 'Enumerable.xxxxxx', only obstructs the // query's actual meaning.
fuente
Es cierto que puede agregar su método (extensión) directamente a su clase. Pero no todas las clases están escritas por ti. Las clases de la biblioteca central o de las bibliotecas de terceros a menudo están cerradas y sería imposible obtener el azúcar sintético sin métodos de extensión. Pero recuerde, los métodos de extensión son como los métodos independientes (estáticos) en eg. c ++
fuente
Los métodos de extensión también pueden ayudar a mantener limpias las clases y las dependencias de clases. Por ejemplo, es posible que necesite un método Bar () para la clase Foo en todos los lugares donde se use Foo. Sin embargo, es posible que desee un método .ToXml () en otro ensamblado y solo para ese ensamblado. En ese caso, puede agregar las dependencias System.Xml y / o System.Xml.Linq necesarias en ese ensamblado y no en el ensamblado original.
Beneficios: las dependencias en su ensamblado de clase de definición se reducen solo a las necesidades básicas y se evitará que otros ensamblados consumidores utilicen el método ToXml (). Consulte esta presentación de PDC para obtener más información.
fuente
Estoy de acuerdo en que los métodos de extensión aumentan la legibilidad del código, pero en realidad no son más que métodos auxiliares estáticos.
En mi opinión, el uso de métodos de extensión para agregar comportamiento a sus clases puede ser:
Confuso: los programadores pueden creer que los métodos son parte del tipo extendido, por lo que no comprenden por qué los métodos desaparecen cuando el espacio de nombres de extensión no se importa.
Un antipatrón: decide agregar comportamiento a los tipos en su marco utilizando métodos de extensión, luego enviándolos a alguna persona para que los realice pruebas unitarias. Ahora está atrapado con un marco que contiene un montón de métodos que no puede falsificar.
fuente
Los métodos de extensión son realmente la incorporación .NET de la refactor "Introducir método extranjero" del Libro de Martin Fowler (hasta la firma del método). Vienen con básicamente los mismos beneficios y trampas. En la sección sobre este refactor, dice que son una solución para cuando no puede modificar la clase que realmente debería poseer el método.
fuente
Principalmente veo los métodos de extensión como una admisión de que quizás no deberían haber rechazado las funciones gratuitas.
En la comunidad de C ++, a menudo se considera una buena práctica de programación orientada a objetos preferir funciones de no miembros libres sobre miembros, porque estas funciones no rompen la encapsulación al obtener acceso a miembros privados que no necesitan. Los métodos de extensión parecen ser una forma indirecta de lograr lo mismo. Es decir, una sintaxis más limpia para funciones estáticas que no tienen acceso a miembros privados.
Los métodos de extensión no son más que azúcar sintáctico, pero no veo ningún daño en su uso.
fuente
fuente
Los uso para reutilizar mis clases de modelo de objetos. Tengo un montón de clases que representan objetos que tengo en una base de datos. Estas clases se utilizan en el lado del cliente solo para mostrar los objetos, por lo que el uso básico es acceder a las propiedades.
public class Stock { public Code { get; private set; } public Name { get; private set; } }
Debido a ese patrón de uso, no quiero tener métodos de lógica empresarial en estas clases, por lo que hago que cada lógica empresarial sea un método de extensión.
public static class StockExtender { public static List <Quote> GetQuotesByDate(this Stock s, DateTime date) {...} }
De esta manera, puedo usar las mismas clases para el procesamiento de la lógica empresarial y para la visualización de la interfaz de usuario sin sobrecargar el lado del cliente con código innecesario.
Una cosa interesante acerca de esta solución es que mis clases de modelo de objetos se generan dinámicamente usando Mono.Cecil , por lo que sería muy difícil agregar métodos de lógica empresarial incluso si quisiera. Tengo un compilador que lee archivos de definición XML y genera estas clases stubs que representan algún objeto que tengo en la base de datos. El único enfoque en este caso es ampliarlos.
fuente
Permite que C # soporte mejor lenguajes dinámicos, LINQ y una docena de otras cosas. Consulte el artículo de Scott Guthrie .
fuente
En mi último proyecto, utilicé el método de extensión para adjuntar métodos Validate () a objetos comerciales. Justifiqué esto porque los objetos comerciales eran objetos de transferencia de datos serializables y se usarán en diferentes dominios, ya que eran entidades de comercio electrónico generales como producto, cliente, comerciante, etc.Bueno, en diferentes dominios las reglas comerciales también pueden ser diferentes, así que encapsulé mi Lógica de validación de enlace tardío en un método de validación adjunto a la clase base de mis objetos de transferencia de datos. Espero que esto tenga sentido :)
fuente
Un caso en el que los métodos de extensión fueron bastante útiles fue en una aplicación cliente que usa servicios web ASMX. Debido a la serialización, los tipos de retorno de métodos web no contienen ningún método (solo las propiedades públicas de estos tipos están disponibles en el cliente).
Los métodos de extensión permitieron su uso para agregar funcionalidad (en el lado del cliente) a los tipos devueltos por los métodos web sin tener que crear otro modelo de objeto o numerosas clases contenedoras en el lado del cliente.
fuente
Los métodos de extensión se pueden utilizar para crear una especie de mezcla en C #.
Esto, a su vez, proporciona una mejor separación de las preocupaciones por los conceptos ortogonales. Eche un vistazo a esta respuesta como ejemplo.
Esto también se puede usar para habilitar roles en C #, un concepto fundamental para la arquitectura DCI .
fuente
También recuerde que los métodos de extensión se agregaron como una forma de ayudar a que las consultas de Linq sean más legibles cuando se usan en su estilo C #.
Estas 2 afectaciones son absolutamente equivalentes, pero la primera es mucho más legible (y la brecha en la legibilidad, por supuesto, aumentaría con más métodos encadenados).
int n1 = new List<int> {1,2,3}.Where(i => i % 2 != 0).Last(); int n2 = Enumerable.Last(Enumerable.Where(new List<int> {1,2,3}, i => i % 2 != 0));
Tenga en cuenta que la sintaxis completa debería ser incluso:
int n1 = new List<int> {1,2,3}.Where<int>(i => i % 2 != 0).Last<int>(); int n2 = Enumerable.Last<int>(Enumerable.Where<int>(new List<int> {1,2,3}, i => i % 2 != 0));
Por casualidad, los parámetros de tipo de
Where
yLast
no necesitan ser mencionados explícitamente ya que se pueden inferir gracias a la presencia del primer parámetro de estos dos métodos (el parámetro que es introducido por la palabra clavethis
y los convierte en métodos de extensión).Este punto es obviamente una ventaja (entre otras) de los métodos de extensión, y puede beneficiarse de él en todos los escenarios similares en los que esté involucrado el encadenamiento de métodos.
Especialmente, es la forma más elegante y convincente que encontré de tener un método de clase base invocable por cualquier subclase y devolver una referencia fuertemente tipada a esta subclase (con el tipo de subclase).
Ejemplo (ok, este escenario es totalmente cursi): después de una buena noche, un animal abre los ojos y luego da un grito; todos los animales abren los ojos de la misma manera, mientras que un perro ladra y un pato kwak.
public abstract class Animal { //some code common to all animals } public static class AnimalExtension { public static TAnimal OpenTheEyes<TAnimal>(this TAnimal animal) where TAnimal : Animal { //Some code to flutter one's eyelashes and then open wide return animal; //returning a self reference to allow method chaining } } public class Dog : Animal { public void Bark() { /* ... */ } } public class Duck : Animal { public void Kwak() { /* ... */ } } class Program { static void Main(string[] args) { Dog Goofy = new Dog(); Duck Donald = new Duck(); Goofy.OpenTheEyes().Bark(); //*1 Donald.OpenTheEyes().Kwak(); //*2 } }
Conceptualmente
OpenTheEyes
debería ser unAnimal
método, pero luego devolvería una instancia de la clase abstractaAnimal
, que no conoce métodos de subclase específicos comoBark
oDuck
lo que sea. Las 2 líneas comentadas como * 1 y * 2 generarían un error de compilación.Pero gracias a los métodos de extensión, podemos tener una especie de "método base que conoce el tipo de subclase en el que se llama".
Tenga en cuenta que un método genérico simple podría haber hecho el trabajo, pero de una manera mucho más incómoda:
public abstract class Animal { //some code common to all animals public TAnimal OpenTheEyes<TAnimal>() where TAnimal : Animal { //Some code to flutter one's eyelashes and then open wide return (TAnimal)this; //returning a self reference to allow method chaining } }
Esta vez, no hay parámetro y, por lo tanto, no es posible inferencia del tipo de retorno. La llamada no puede ser otra que:
... lo que puede pesar mucho el código si se involucra más encadenamiento (especialmente sabiendo que el parámetro de tipo siempre estará
<Dog>
en la línea de Goofy y<Duck>
en la de Donald ...)fuente
Solo tengo una palabra que decir al respecto: MANTENIMIENTO esta es la clave para el uso de métodos de extensión
fuente
Creo que los métodos de extensión ayudan a escribir un código más claro.
En lugar de poner un nuevo método dentro de su clase, como sugirió su amigo, póngalo en el espacio de nombres ExtensionMethods. De esta manera mantendrá un sentido lógico de orden en su clase. Los métodos que realmente no tratan directamente con su clase no la abarrotarán.
Siento que los métodos de extensión hacen que su código sea más claro y organizado de manera más apropiada.
fuente
Permite que su editor / IDE realice sugerencias de autocompletado de manera inteligente.
fuente
Me encantan por construir html. Con frecuencia, hay secciones que se utilizan repetidamente o se generan de forma recursiva en las que una función es útil pero de otra manera interrumpiría el flujo del programa.
HTML_Out.Append("<ul>"); foreach (var i in items) if (i.Description != "") { HTML_Out.Append("<li>") .AppendAnchor(new string[]{ urlRoot, i.Description_Norm }, i.Description) .Append("<div>") .AppendImage(iconDir, i.Icon, i.Description) .Append(i.Categories.ToHTML(i.Description_Norm, urlRoot)).Append("</div></li>"); } return HTML_Out.Append("</ul>").ToString();
También hay situaciones en las que un objeto necesita lógica personalizada para estar preparado para la salida HTML; los métodos de extensión le permiten agregar esta funcionalidad sin mezclar presentación y lógica dentro de la clase.
fuente
Descubrí que los métodos de extensión son útiles para hacer coincidir argumentos genéricos anidados.
Eso suena un poco extraño, pero digamos que tenemos una clase genérica
MyGenericClass<TList>
y sabemos que TList en sí es genérico (por ejemplo, unList<T>
), no creo que haya una manera de extraer esa 'T' anidada de la Lista sin ninguna extensión métodos o métodos auxiliares estáticos. Si solo tenemos métodos auxiliares estáticos a nuestra disposición, es (a) feo y (b) nos obligará a mover la funcionalidad que pertenece a la clase a una ubicación externa.por ejemplo, para recuperar los tipos en una tupla y convertirlos en una firma de método, podemos usar métodos de extensión:
public class Tuple { } public class Tuple<T0> : Tuple { } public class Tuple<T0, T1> : Tuple<T0> { } public class Caller<TTuple> where TTuple : Tuple { /* ... */ } public static class CallerExtensions { public static void Call<T0>(this Caller<Tuple<T0>> caller, T0 p0) { /* ... */ } public static void Call<T0, T1>(this Caller<Tuple<T0, T1>> caller, T0 p0, T1 p1) { /* ... */ } } new Caller<Tuple<int>>().Call(10); new Caller<Tuple<string, int>>().Call("Hello", 10);
Dicho esto, no estoy seguro de dónde debería estar la línea divisoria: ¿cuándo debería ser un método un método de extensión y cuándo debería ser un método auxiliar estático? ¿Alguna idea?
fuente
Tengo zonas de entrada en mi pantalla y todas deben implementar un comportamiento estándar, sean cuales sean sus tipos exactos (cuadros de texto, casillas de verificación, etc.). No pueden heredar una clase base común ya que cada tipo de zona de entrada ya deriva de una clase específica (TextInputBox, etc.)
Tal vez al subir en la jerarquía de herencia podría encontrar un ancestro común como, por ejemplo, WebControl, pero no desarrollé la clase de marco WebControl y no expone lo que necesito.
Con el método de extensión, puedo:
1) ampliar la clase WebControl y luego obtener mi comportamiento estándar unificado en todas mis clases de entrada
2) alternativamente, hacer que todas mis clases se deriven de una interfaz, digamos IInputZone, y extender esta interfaz con métodos. Ahora podré llamar a métodos de extensiones relacionados con la interfaz en todas mis zonas de entrada. Por lo tanto, logré una especie de herencia múltiple, ya que mis zonas de entrada ya derivaban de múltiples clases base.
fuente
Hay tantos ejemplos excelentes de métodos de extensión ... especialmente en IEnumerables como se publicó anteriormente.
por ejemplo, si tengo un
IEnumerable<myObject>
método de puedo crear y extensión paraIEnumerable<myObject>
... crea la lista
Sin los métodos de extensión tendrían que llamar a:
myDisplayMethod(myOldArray); // can create more nexted brackets.
¡Otro gran ejemplo es la creación de una lista enlazada circular en un instante!
¡Puedo tomarme el crédito por ello!
lista enlazada circular usando métodos de extensión
Ahora combine estos y el código de Métodos de extensión se lee como sigue.
más bien que
usando métodos de extensión Es más ordenado y más fácil de leer y más orientado a objetos. también muy cerca de:
¡Muéstrale eso a tu colega! :)
fuente