C# Language Métodos de extensión - descripción general


Ejemplo

Los métodos de extensión se introdujeron en C # 3.0. Los métodos de extensión extienden y agregan comportamiento a los tipos existentes sin crear un nuevo tipo derivado, recompilando o modificando el tipo original. Son especialmente útiles cuando no puede modificar la fuente de un tipo que desea mejorar. Se pueden crear métodos de extensión para los tipos de sistema, los tipos definidos por terceros y los tipos que usted mismo haya definido. El método de extensión se puede invocar como si fuera un método miembro del tipo original. Esto permite el método de encadenamiento utilizado para implementar una interfaz fluida .

Se crea un método de extensión agregando un método estático a una clase estática que es distinta del tipo original que se extiende. La clase estática que contiene el método de extensión a menudo se crea con el único propósito de mantener métodos de extensión.

Los métodos de extensión toman un primer parámetro especial que designa el tipo original que se está extendiendo. Este primer parámetro está decorado con la palabra clave this (que constituye un uso especial y distinto de this en C #; debe entenderse como diferente del uso de this que permite referirse a miembros de la instancia de objeto actual).

En el siguiente ejemplo, el tipo original que se extiende es la string clase. String se ha extendido mediante un método Shorten() , que proporciona la funcionalidad adicional de acortamiento. La clase estática StringExtensions se ha creado para contener el método de extensión. El método de extensión Shorten() muestra que es una extensión de string través del primer parámetro especialmente marcado. Para mostrar que el método Shorten() extiende la string , el primer parámetro se marca con this . Por lo tanto, la firma completa del primer parámetro es el this string text , donde la string es el tipo original que se extiende y el text es el nombre del parámetro elegido.

static class StringExtensions
{
    public static string Shorten(this string text, int length) 
    {
        return text.Substring(0, length);
    }
}

class Program
{
    static void Main()
    {
        // This calls method String.ToUpper()
        var myString = "Hello World!".ToUpper();

        // This calls the extension method StringExtensions.Shorten()
        var newString = myString.Shorten(5); 

        // It is worth noting that the above call is purely syntactic sugar
        // and the assignment below is functionally equivalent
        var newString2 = StringExtensions.Shorten(myString, 5);
    }
}

Demo en vivo en .NET Fiddle


El objeto pasado como primer argumento de un método de extensión (que está acompañado por this palabra clave) es la instancia a la que se llama el método de extensión.

Por ejemplo, cuando este código se ejecuta:

"some string".Shorten(5);

Los valores de los argumentos son los siguientes:

text: "some string"
length: 5

Tenga en cuenta que los métodos de extensión solo se pueden usar si están en el mismo espacio de nombres que su definición, si el espacio de nombres se importa explícitamente mediante el código que usa el método de extensión, o si la clase de extensión no tiene espacio de nombres. Las pautas del marco .NET recomiendan colocar las clases de extensión en su propio espacio de nombres. Sin embargo, esto puede llevar a problemas de descubrimiento.

Esto no genera conflictos entre los métodos de extensión y las bibliotecas que se están utilizando, a menos que se incluyan explícitamente los espacios de nombres que puedan entrar en conflicto. Por ejemplo, las Extensiones LINQ :

using System.Linq; // Allows use of extension methods from the System.Linq namespace

class Program
{
    static void Main()
    {
        var ints = new int[] {1, 2, 3, 4};

        // Call Where() extension method from the System.Linq namespace
        var even = ints.Where(x => x % 2 == 0); 
    }
}

Demo en vivo en .NET Fiddle


Desde C # 6.0, también es posible poner una directiva using static a la clase que contiene los métodos de extensión. Por ejemplo, using static System.Linq.Enumerable; . Esto hace que los métodos de extensión de esa clase en particular estén disponibles sin traer otros tipos del mismo espacio de nombres al alcance.


Cuando un método de clase con la misma firma está disponible, el compilador lo prioriza sobre la llamada al método de extensión. Por ejemplo:

class Test
{
   public void Hello()
   {
       Console.WriteLine("From Test");
   }
}

static class TestExtensions
{
    public static void Hello(this Test test)
    {
        Console.WriteLine("From extension method");
    }
}

class Program
{
    static void Main()
    {
        Test t = new Test();
        t.Hello(); // Prints "From Test"
    }
}

Demo en vivo en .NET Fiddle


Tenga en cuenta que si hay dos funciones de extensión con la misma firma, y ​​una de ellas se encuentra en el mismo espacio de nombres, se asignará prioridad a esa. Por otro lado, si se accede a ambos using , se producirá un error de tiempo de compilación con el mensaje:

La llamada es ambigua entre los siguientes métodos o propiedades.


Tenga en cuenta que la conveniencia sintáctica de llamar a un método de extensión a través de originalTypeInstance.ExtensionMethod() es una conveniencia opcional. El método también se puede llamar de la manera tradicional, de modo que el primer parámetro especial se utiliza como parámetro del método.

Es decir, ambos de los siguientes trabajos:

//Calling as though method belongs to string--it seamlessly extends string
String s = "Hello World";
s.Shorten(5);  

//Calling as a traditional static method with two parameters
StringExtensions.Shorten(s, 5);