Menú de navegaciónMenú
Categorías

La mejor forma de Aprender Programación online y en español www.campusmvp.es

Métodos de Extensión en C#

Cuando deseamos añadir un nuevo método a una clase existente, típicamente editamos el código fuente de la misma, si disponemos de acceso al mismo, o creamos una clase derivada y añadimos en ella el nuevo método. Cuando esto no es factible por alguna razón (por ejemplo, si es una clase de tipo sealed), podemos recurrir a los métodos de extensión.

A la hora de definirlos, los métodos de extensión tienen el mismo aspecto que los métodos estáticos, con la diferencia de que su primer argumento lleva antepuesta la palabra clave this (que en este contexto no tiene nada que ver con el this que habitualmente utilizamos para tomar una referencia a la instancia actual).

A la hora de llamar al método, no escribimos ese argumento. En su lugar, el compilador toma la instancia del objeto sobre la que estamos llamando al método. Por ejemplo:

public static class Extensores
{
    public static int ContarPalabras(this string texto)
    {
        return texto.Split(' ').Length;
    }
} 

Podemos ver que se trata de un método estático definido dentro de una clase estática. Para que funcione el método de extensión es obligatorio que tanto el método como la clase sean static.
Para llamar al método, lo invocamos desde cualquier cadena, como si el método formase parte de la clase string (el tipo de argumento que va detrás del this en la declaración):

 static void Main(string[] args)
{
    string ejemplo = "Esta frase tiene cinco palabras.";
    int n = ejemplo.ContarPalabras();
    Console.WriteLine("Hay {0} palabras.", n);
} 

La llamada a ContarPalabras se realiza sobre la cadena ejemplo de la misma manera que si fuera alguno de los métodos estándar de la clase string . Desde el punto de vista del código llamante, no se nota ninguna diferencia respecto a los métodos nativos de la clase.

Al teclear el código en Visual Studio, intellisense muestra el método de extensión en la misma lista que el resto de los métodos, pero se ilustra con un icono ligeramente distinto para que podamos reconocer visualmente que se trata de un método de extensión.

Metodo-de-Extension

En la anterior imagen vemos varios métodos de extensión (los que tienen una flecha azul), además del método ContarPalabras que nosotros hemos escrito. Estos métodos provienen de las librerías de System.Linq, que estaban referenciadas mediante un using al principio del programa del que se copió el ejemplo de la figura.

No solo se pueden generar métodos de extensión sobre una clase, sino también sobre una interfaz. De esta manera, todas las demás clases que hereden de esa clase, o que implementen esa interfaz, recibirán el método de extensión.

Los métodos de extensión también pueden ser genéricos. Por ejemplo, en System.Linq hay  varios métodos de extensión que extienden la interfaz IEnumerable<T> de una forma similar a esta:

 public static string Combinar<T>(this IEnumerable<T> ien)
{
    StringBuilder sb = new StringBuilder();
    foreach (T item in ien)
    {
        sb.Append(item.ToString());
    }
    return sb.ToString();
}

Después de definir este método, se puede invocar sobre cualquier objeto que implemente la interfaz IEnumerable<T>, por ejemplo, sobre un List<int>, que implementa IEnumerable<int>:

List<int> lista = new List<int>{ 9,8,7,6 };
Console.WriteLine(lista.Combinar());

Si se desea, se pueden añadir argumentos adicionales en los métodos de extensión. Después, en la llamada al método, esos argumentos se indican con normalidad entre los paréntesis, como si se hubiese declarado el método sin el argumento “this”.

 public static int ContarPalabras(this string texto, char separador)
{
    return texto.Split(separador).Length;
}

string ejemplo = "Hola, mundo. ¿Qué tal?";
int n = ejemplo.ContarPalabras(',');
Console.WriteLine(n); //Escribe "2" 

Es sencillo añadir métodos de extensión en nuestros programas, pero se recomienda no abusar de este mecanismo ya que puede ocasionar una pérdida de claridad y mantenibilidad del código, al aparecer en las clases métodos que no figuran dentro del código fuente de las mismas.

Una aplicación común de los métodos de extensión consiste en extender interfaces tales como IEnumerable definiéndoles métodos tales como Where, Select u OrderBy, que luego permiten utilizar sentencias LINQ sobre cualquier objeto que implemente la interfaz en cuestión.

Alberto Población Alberto es MVP de C#, y lleva varias décadas desarrollando software. Cuenta entre otras con las certificaciones MCSE, MCDBA, MCITP, MCSD, MCPD. En la actualidad trabaja como consultor independiente dedicándose también a la formación. Es instructor certificado por Microsoft. Ver todos los posts de Alberto Población
Archivado en: Lenguajes y plataformas

Boletín campusMVP.es

Solo cosas útiles. Una vez al mes.

🚀 Únete a miles de desarrolladores

DATE DE ALTA

x No me interesa | x Ya soy suscriptor

La mejor formación online para desarrolladores como tú

Comentarios (8) -

Hola. Tengo varios métodos extensores y todos funcionan muy bien, pero tengo problema con uno, haber si me puedes ayudar. Saludos.

  public static string numbersOnly(this string s)
        {
            return Regex.Replace(s, @"[^\d.,]", "");
        }

Si hago esto no funciona

textBox1.Text.numbersOnly();

pero si lo llamo como a cualquier otro método si funciona.

            textBox1.Text = _String.numbersOnly(textBox1.Text);


Responder

José Manuel Alarcón
José Manuel Alarcón

Hola:

¿Por qué dices que no te funciona? ¿Te da un error?

Debería funcionar sin problema. Quizá si lo que quieres es que cambie directamente el contenido del cuadro de texto, eso no te lo hace, debes hacer la asignación también además de llamar al método, así:

textBox1.Text = textBox1.Text.numbersOnly();

Pero te funciona.

Saludos.

Responder

Hola. Muchas gracias, ahí estaba el error. Saludos.

Responder

De paso, queda el método por si a alguien le sirve.
Es el método más simple que se me ocurrió, obvio luego hay que comprobar si es un número válido, de acuerdo a lo esperado, el método solo te devuelve la parte numérica de una un string, teniendo en cuenta el punto (.) y la coma (,).

Responder

José Manuel Alarcón
José Manuel Alarcón

Hola de nuevo:

Generalmente si lo que quieres es evitar que los usuarios introduzcan números, lo mejor es interceptar un evento (lo habitual KeyUp o KeyDown aunque pueden valer otros) y en éstos denegar la pulsación de los códigos correspondientes a valores numéricos. De hecho en la MSDN es justo el ejemplo que viene para estos eventos:

msdn.microsoft.com/.../...l.keydown(v=vs.110).aspx

Saludos!

Responder

Muchas gracias.  Pero este no era el caso obtenia una cadena y solo se tiene certeza de que es un numero pero pueden contener otros caracteres y no necesariamente siempre formateado de la misma manera.  

Estoy tratando de aprender bien c# y poo   a fondo más que nada.  Programar programo hace mucho.  

Gracias por tus aportes.  Que tengas un buen día.

Responder

Perdon es la hora es de madrugada por aquí. Solo use un texBox solo para probar los metodos extensores y las funciones regulares. Solo lo use a modo de test.  

Responder

Manuel Rivera
Manuel Rivera

Acabo  de leer tu artículo sobre los extension m e t h o d s   e n   e s t e   s i t i o   a qu i   y   a g r a d e c i d o   e s t o y   p o r   e s t a   p u b li c a c i ó n ,   A u n   m e   q u e d a n   a l g u n a s   d u d as   p u e s   p o r   p r i m e r a   v e z   e s t o y   u s a n d o
l o s   e x t e n s i ó n   m e t h o d s     y   a   l a   v e r d a d   n o   t e n g o   m u c h a   a y u d a   e n   e s t e   s e n t i d o .

T e n g o   e s t a   c l a s e   E x t e n s o r . c s

static class Extensors
    {
        // Sum<int>: Computes the sum of a sequence of int values.
        public static int MySum(this IEnumerable<int> source)   // error: the bodey of this method cannot be an iterator block
                                                                                                                because int is not iterator interface type
        {
            
            var res = source.GetEnumerator().Current;
            foreach (var item in source)
            {
                res += item;
                yield return res;
            }
        }


A h í   p u e d e   v e r   e l   e r r o r   q u e   m e   e s t á    l a n z a n d o   a l   c r e a r   e l   p r i m e r   m e t h o d .
M u c h a s   G r a c i a s       por adelantado ,

Manuel Rivera

Responder

Agregar comentario

Los datos anteriores se utilizarán exclusivamente para permitirte hacer el comentario y, si lo seleccionas, notificarte de nuevos comentarios en este artículo, pero no se procesarán ni se utilizarán para ningún otro propósito. Lee nuestra política de privacidad.