96 - Métodos de extensión


Otra de las características del lenguaje C# es el concepto de métodos de extensión.

Mediante los métodos de extensión C# nos permite agregar otros métodos a una clase existente sin tener que heredar de la misma.
Con una serie de ejemplos quedará claro esta característica.

Problema

Agregar dos métodos a la clase string que permitan recuperar la primer mitad y la segunda mitad.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MetodosExtension1
{
    public static class Extension
    {
        public static string MitadPrimera(this string cadena)
        {
            return cadena.Substring(0, cadena.Length / 2);
        }

        public static string MitadSegunda(this string cadena)
        {
            return cadena.Substring(cadena.Length / 2, cadena.Length / 2);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            string cadena1 = "Viento";
            Console.WriteLine(cadena1.MitadPrimera());
            Console.WriteLine(cadena1.MitadSegunda());
            Console.ReadKey();
        }
    }
}

Para definir un método de extensión debemos declarar una clase static y dentro de la misma declarar el método de extensión que también debe ser estático.

La clase Extension declara el método MitadPrimera e indicamos en el primer parámetro a que clase estamos extendiendo:

        public static string MitadPrimera(this string cadena)
        {
            return cadena.Substring(0, cadena.Length / 2);
        }

El método MitadPrimero extiende la clase string (lo indicamos mediante la palabra clave this y el nombre de la clase a extender)

Dentro del método el parámetro cadena tiene acceso al objeto propiamente dicho, en nuestro ejemplo queremos que el método MitadPrimera retorne la primera mitad de caracteres del string.

Ahora cuando definamos un objeto de la clase string podremos comprobar que dicha clase tiene un método llamamdo MitadPrimero:

            string cadena1 = "Viento";
            Console.WriteLine(cadena1.MitadPrimera());

De forma similar definimos el segundo método de extensión que retorna la segunda parte de un string:

        public static string MitadSegunda(this string cadena)
        {
            return cadena.Substring(cadena.Length / 2, cadena.Length / 2);
        }

La llamada al método MitadSegunda:

            Console.WriteLine(cadena1.MitadSegunda());

El nombre que le dimos a la clase que define los métodos de extensión puede ser cualquiera, pero es obligatorio que sea declarada de tipo static.

Problema

Agregar un método de extensión a la clase List que permita imprimir todos los elementos de la lista. El método de extensión debe ser genérico.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MetodosExtension2
{
    public static class Extension
    {
        public static void Imprimir<T>(this List<T> lista)
        {
            foreach (var elemento in lista)
                Console.Write("{0} ", elemento);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<int> lista1 = new List<int>();
            lista1.Add(10);
            lista1.Add(20);
            lista1.Add(30);
            lista1.Add(500);
            lista1.Add(400);
            lista1.Imprimir();
            Console.ReadKey();
        }
    }
}

Recordar que todo método de extensión debe ser static y debe estar declarado dentro de una clase static:

    public static class Extension
    {
        public static void Imprimir<T>(this List<T> lista)

El método Imprimir se lo agregamos a la clase: List<T>, como se trata de una clase genérica debemos indicar dicha situación <T>. Dentro del método mostramos mediante una estructura repetitiva foreach todos los elementos de la colección:

            foreach (var elemento in lista)
                Console.Write("{0} ", elemento);

Para llamar a este método debemos crear un objeto de la clase List con cualquier tipo de dato:

            List<int> lista1 = new List<int>();
            lista1.Add(10);
            lista1.Add(20);
            lista1.Add(30);
            lista1.Add(500);
            lista1.Add(400);
            lista1.Imprimir();

Problema

Agregar un método de extensión a la clase int que permita imprimir desde el valor actual que tiene la variable entera hasta el valor que le pasemos como parámetro, de uno en uno.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MetodosExtension3
{
    public static class Extension
    {
        public static void ImprimirHasta(this int valor, int fin)
        {
            for (var inicio = valor; inicio <= fin; inicio++)
                Console.Write("{0} ", inicio);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            10.ImprimirHasta(30);
            Console.WriteLine();
            int va = 100;
            va.ImprimirHasta(150);
            Console.ReadKey();
        }
    }
}

El método de extensión ImprimirHasta extiende la clase int: this int valor y recibe un parámetro de tipo int:

        public static void ImprimirHasta(this int valor, int fin)

Dentro del método comenzamos a imprimir desde el valor actual que almacena el objeto int hasta el valor indicado por el parámetro fin:

            for (var inicio = valor; inicio <= fin; inicio++)
                Console.Write("{0} ", inicio);

Para llamar al método lo debemos hacer a partir de un objeto de la clase int como puede ser:

            10.ImprimirHasta(30);

El 10 es un objeto de la clase int y por lo tanto se le ha agregado el método ImprimirHasta.

También podemos definir un objeto de la clase int y llamar luego al método ImprimirHasta:

            int va = 100;
            va.ImprimirHasta(150);

No hay que confundir que el método de extensión tiene en principio 2 parámetros y cuando lo llamamos le pasamos uno:

        public static void ImprimirHasta(this int valor, int fin)
        ....
        ....
            va.ImprimirHasta(150);

Es importante tener en cuenta que this int valor recibe el objeto "va" y el parámetro int fin recibe el valor 150.


Retornar