
“Los métodos de extensión permiten “agregar” métodos a los tipos existentes sin necesidad de crear un nuevo tipo derivado y volver a compilar o sin necesidad de modificar el tipo original. Los métodos de extensión constituyen un tipo especial de método estático, pero se les llama como si se tratasen de métodos de instancia en el tipo extendido. En el caso del código de cliente escrito en C# y Visual Basic, no existe ninguna diferencia aparente entre llamar a un método de extensión y llamar a los métodos realmente definidos en un tipo.” MSDN
Ciertamente esta es una descripción bastante criptica de esta técnica de desarrollo que se puede utilizar para una mayor productividad y legibilidad de nuestro código. Por ello quiero escribir un artículo que, por medio de un ejemplo muy sencillo, pueda ser un paso inicial en el conocimiento de esta herramienta de programación.
Básicamente, y para entendernos de una forma más sencilla. Un método extensor es una forma de “añadirle“ métodos a una clase sin necesidad de hacerlo en la original o en alguna instancia/copia de la misma. No es un reemplazo de la técnica formal por medio de herencia, si no una pequeña “trampa” que nos permite obtener un resultado muy similar.
Actualmente estoy utilizando como editor principal el Visual Studio 11 Beta, que no cuesta ni un real (pero lo costará). Pero si quisiera un producto gratuito para programar en C# podría también utilizar el Visual Studio Express 11.
Para este artículo me creo un nuevo proyecto Web, de tipo MVC4 (que también es beta) vacío. He elegido este tipo para no tener ningún tipo de ruido en el ejemplo que quiero compartir. Por ello me voy a saltar la regla de hacer siempre test unitarios, y no voy a construir el proyecto de testing.
A continuación añado una página de clases en la carpeta de Modelo, llamada Comprobaciones, en donde voy a insertar una clase que realice diversas comprobaciones básicas y en donde voy a definir métodos extensores que me haga el código más legible.
El primer paso de mi ejemplo es enunciarlo. Describir la visión de lo que quiero hacer. Y esto es realizar una clase que me compruebe si los datos de un objeto Persona son correctos. La Persona va a tener dos propiedades: el nombre y la edad en años. Y por ello lo primero que voy a hacer es construir la estructura del objeto.
public class Persona
{
public string Nombre { get; set; }
public int Edad { get; set; }
}
public class Comprobaciones
{
public bool esCorrecto(Persona persona)
{
return persona != null;
}
}
public static class Extensores
{
public static Boolean IsNotNull(this Persona persona)
{
return persona != null;
}
}
public class Comprobaciones
{
public bool esCorrecto(Persona persona)
{
return persona.IsNotNull();
}
}
public static Boolean IsNotNull(this Object objeto)
{
return objeto != null;
}
public class Comprobaciones
{
public bool esCorrecto(Persona persona)
{
return persona.Edad.IsNotNull();
}
}
public class Comprobaciones
{
public bool esCorrecto(Persona persona)
{
return string.IsNullOrEmpty(persona.Nombre) == false
&& string.IsNullOrWhiteSpace(persona.Nombre);
}
}
public static Boolean NoTieneNombre(this Persona persona)
{
return string.IsNullOrEmpty(persona.Nombre)
&& string.IsNullOrWhiteSpace(persona.Nombre);
}
public class Comprobaciones
{
public bool esCorrecto(Persona persona)
{
return persona.NoTieneNombre();
}
}Primero el código es dependiente del intellisense del Visual Studio, ya que desde el fichero fuente abierto no puedes saber si el método invocado es parte de la instancia o es un método extensor. Lo cual puede causar dolores de cabeza para localizar el código si no estás con el IDE adecuado.
Otro problema es que el ciclo de vida de la clase y de los métodos que la extiende pueden ser totalmente diferentes. Por lo cual un extensor que funcione bien en un momento, por un cambio en el objeto que extiende puede dejar de hacerlo correctamente.
Por último si se realiza un cambio en la clase extendida y se le añade un método de instancia con el mismo nombre que el método extensor, este dejará de funcionar ya que el compilador utilizará antes el método de instancia que el extensor. Lo cual es un error muy difícil de localizar.
A causa de ello, se aconseja darle prioridad al uso de los métodos de instancia y a la herencia, antes que a los métodos extensores. Lo cual no quita que herramientas como Linq esté construida en su totalidad con esta técnica de desarrollo.
Ahora solo queda, probar y practicar, para tener un conocimiento en más profundidad que te permita tomar las decisiones más productivas.
namespace GenbetaDevMVC4.Models
{
public class Persona
{
public string Nombre { get; set; }
public int Edad { get; set; }
}
public class Comprobaciones
{
public bool esCorrecto(Persona persona)
{
return ! persona.NoTieneNombre();
}
}
public static class Extensores
{
public static Boolean IsNotNull(this Object objeto)
{
return objeto != null;
}
public static Boolean NoTieneNombre(this Persona persona)
{
return string.IsNullOrEmpty(persona.Nombre)
&& string.IsNullOrWhiteSpace(persona.Nombre);
}
}
}
03/05/2012 He añadido un enlace a una biblioteca de métodos extensores que será de gran utilidad.
Más información | Métodos de extensión (Guía de programación de C#), Extension Method