Introducción a Metodos de Extensión

El .NET Framework 3.5, el cual fue lanzado en el 2007, introdujo el concepto de Metodos de Extensión.

Los métodos de extensión nos permiten agregar nuevos métodos a un clase existente, sin la necesidad de hacer cambios a la clase o de tener que heredar de la clase.

Los métodos de extensión le permitieron a lo programadores de Microsoft agregar mucha mas funcionalidad a clases existentes en la librería de clases base de .NET. Un buen ejemplo es LINQ, del cual hablaremos en otra ocasión.

Cuando nosotros creamos un método de extensión, definimos un método estático (compartido). Pero cuando invoquemos el método de extensión, parecerá como un método mas de la clase original.

Por favor observa que el método de extensión no necesita estar definido en el mismo ensamblado o espacio de nombres donde la clase original se encuentra definida.

A pesar de que el método de extensión es invocado como si fuera parte de la clase, en realidad no es un método de la clase. Recuerda que realmente estamos definiendo un método estático, lo que significa que no podemos acceder miembros privados de clase, solo miembros públicos.

Además, si defines un método de extensión con el mismo nombre que un método existente de la clase, el método original será invocado, no el método de extensión. Pero no recibirás ningún error del compilador.

Ahora veamos un ejemplo.

Supongamos que tenemos la siguiente clase definida, la cual ya usamos en una de nuestras aplicaciones.

using System;
using System.Collections.Generic;

namespace Example.Business
{
    public class Orden
    {
        //propiedades
        public int ID { get; set; }
        public Cliente Cliente { get; set; }
        public IList<Producto> Articulos { get; set; }

        //constructor vacio
        public Orden()
        { }

        public Decimal ObtenerTotal()
        {
            Decimal total = 0;
            //iterar por cada articulo y sumar
            foreach (Producto item in Articulos)
            {
                total += item.Cantidad * item.PrecioUnitario;
            }
            return total;
        }

        public void Guardar(String archivoNombre)
        {
            Console.WriteLine("Orden guardada a {0}", archivoNombre);
        }

        public void Imprimir()
        {
            Console.WriteLine("Orden impresa");
        }

    }

    public class Cliente
    {
        //propiedades
        public int ID { get; set; }
        public String Nombre { get; set; }
        public String Direccion { get; set; }

        //constructor vacio
        public Cliente()
        { }

        //constructor sin parametros
        public Cliente(int id, String nombre, String direccion)
        {
            ID = id;
            Nombre = nombre;
            Direccion = direccion;
        }
    }

    public class Producto
    {
        //propiedades
        public int ID { get; set; }
        public String Descripcion { get; set; }
        public Decimal PrecioUnitario { get; set; }
        public int Cantidad { get; set; }

        //constructor vacio
        public Producto()
        { }

        //constructor sin parametros
        public Producto(int id, String descripcion, Decimal precioUnitario, int cantidad)
        {
            ID = id;
            Descripcion = descripcion;
            PrecioUnitario = precioUnitario;
            Cantidad = cantidad;
        }
    }
}

La clase contiene información de orden, y tiene métodos para obtener el total de la orden, imprimir la orden y guardar la orden a un archivo.

Aquí hay un código haciendo uso de esta clase.

using System;
using System.Collections.Generic;

namespace Example
{
    using Business;

    class Program
    {
        static void Main(string[] args)
        {
            //crear orden
            Orden orden = new Orden();
            orden.Cliente = new Cliente(1001, "Oscar Martinez", "555 Test St");
            orden.Articulos = new List<Producto>();
            orden.Articulos.Add(new Producto(101, "Consola XBox", 249.90m, 1));
            orden.Articulos.Add(new Producto(101, "Control para XBox", 39.90m, 2));

            Console.WriteLine("Total: {0}", orden.ObtenerTotal());

            orden.Guardar("test.txt");
            orden.Imprimir();

            Console.Write("\n\nPresiona cualquier tecla para salir...");
            Console.ReadKey();
        }

    }
}

Esta es la salida.

Salida de consola

Ahora supongamos que necesitamos crear una interfaz con un vendedor, y es necesario crear un servicio web. Vamos a intercambiar información de orden en formato XML.

Nos gustaría poder re-utilizar la clase Orden, y seria muy útil tener un método para serializar la clase a XML.

Vamos a crear un par de métodos de extensión.

using System;
using System.Text;

namespace Example.Extensions
{
    using Business;
    public static class OrderExtensions
    {
        public static String ToXml(this Orden orden)
        {
            StringBuilder str = new StringBuilder();

            str.AppendFormat("<Orden id=\"{0}\" total=\"{1}\">\n", orden.ID, orden.ObtenerTotal());
            str.AppendFormat("\t<Cliente id=\"{0}\" nombre=\"{1}\">\n", orden.Cliente.ID, orden.Cliente.Nombre);
            str.Append("\t</Cliente>\n</Orden>");

            return str.ToString();
        }

        public static void ToXml(this Orden orden, out String xml)
        {
            xml = orden.ToXml();
        }
    }
}

Observa el primer parámetro de ambos métodos. La palabra clave this justo antes del tipo de parámetro es lo que conecta nuestro método estático con la clase Orden.

Aquí hay un código utilizando los nuevos métodos.

using System;
using System.Collections.Generic;
using Example.Extensions;

namespace Example
{
    using Business;

    class Program
    {
        static void Main(string[] args)
        {
            //crear orden
            Orden orden = new Orden();
            orden.Cliente = new Cliente(1001, "Oscar Martinez", "555 Test St");
            orden.Articulos = new List<Producto>();
            orden.Articulos.Add(new Producto(101, "Consola XBox", 249.90m, 1));
            orden.Articulos.Add(new Producto(101, "Control para XBox", 39.90m, 2));

            String xml;
            orden.ToXml(out xml);

            xml = orden.ToXml();

            Console.WriteLine(xml);

            Console.Write("\n\nPresiona cualquier tecla para salir...");
            Console.ReadKey();
        }

    }
}

Los métodos de extensión fueron definidos en el espacio de nombres Example.Extensions, y en cuanto importamos este espacio de nombres, los nuevos métodos están disponibles para nosotros.

A pesar de que definimos un método con un parámetro y otro método con dos parámetros, terminamos con un método sin parámetros y otro método con un solo parámetro. Esto es porque el primer parámetro solo se utiliza para conectar el método de extensión con la clase Orden.

Esta es la salida.

Salida de consola

Por favor deja tus comentarios si tienes alguna pregunta.

Recibir Actualizaciones Gratis
Entradas Relacionadas
Comentarios