C# Language Metodi di estensione: panoramica


Esempio

I metodi di estensione sono stati introdotti in C # 3.0. I metodi di estensione estendono e aggiungono comportamenti a tipi esistenti senza creare un nuovo tipo derivato, ricompilando o modificando in altro modo il tipo originale. Sono particolarmente utili quando non è possibile modificare la fonte di un tipo che si desidera migliorare. I metodi di estensione possono essere creati per tipi di sistema, tipi definiti da terze parti e tipi definiti dall'utente. Il metodo di estensione può essere invocato come se fosse un metodo membro del tipo originale. Ciò consente di concatenare il metodo utilizzato per implementare un'interfaccia fluida .

Un metodo di estensione viene creato aggiungendo un metodo statico a una classe statica distinta dal tipo originale che viene esteso. La classe statica che contiene il metodo di estensione è spesso creata al solo scopo di contenere i metodi di estensione.

I metodi di estensione prendono uno speciale primo parametro che designa il tipo originale che viene esteso. Questo primo parametro è decorato con la parola chiave this (che costituisce un uso speciale e distinto di this in C # -it dovrebbe essere compreso come differente dall'uso di this che consente di fare riferimento ai membri dell'istanza dell'oggetto corrente).

Nell'esempio seguente, il tipo originale che è esteso è la string classe. String è stata estesa da un metodo Shorten() , che fornisce le funzionalità aggiuntive di accorciamento. La classe statica StringExtensions è stata creata per contenere il metodo di estensione. Il metodo di estensione Shorten() mostra che si tratta di un'estensione della string tramite il primo parametro appositamente contrassegnato. Per mostrare che il metodo Shorten() estende la string , il primo parametro è contrassegnato da this . Pertanto, la firma completa del primo parametro è this string text , dove string è il tipo originale che viene esteso e il text è il nome del parametro scelto.

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);
    }
}

Live Demo su .NET Fiddle


L'oggetto passato come primo argomento di un metodo di estensione (che è accompagnato dalla parola chiave this ) è l'istanza in cui viene chiamato il metodo di estensione.

Ad esempio, quando viene eseguito questo codice:

"some string".Shorten(5);

I valori degli argomenti sono i seguenti:

text: "some string"
length: 5

Si noti che i metodi di estensione sono utilizzabili solo se si trovano nello stesso spazio dei nomi della loro definizione, se lo spazio dei nomi viene importato in modo esplicito dal codice utilizzando il metodo di estensione o se la classe di estensione non ha spazio dei nomi. Le linee guida di .NET framework raccomandano di inserire le classi di estensione nel proprio spazio dei nomi. Tuttavia, questo può portare a problemi di scoperta.

Ciò non provoca conflitti tra i metodi di estensione e le librerie utilizzate, a meno che gli spazi dei nomi che potrebbero essere in conflitto siano esplicitamente inseriti. Ad esempio, LINQ Estensioni :

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); 
    }
}

Live Demo su .NET Fiddle


Dal momento che C # 6.0, è anche possibile inserire una direttiva using static la classe che contiene i metodi di estensione. Ad esempio, using static System.Linq.Enumerable; . Ciò rende i metodi di estensione da quella particolare classe disponibile senza portare altri tipi dallo stesso spazio dei nomi in ambito.


Quando un metodo di classe con la stessa firma è disponibile, il compilatore dà la priorità alla chiamata del metodo di estensione. Per esempio:

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 dal vivo su .NET Fiddle


Notare che se ci sono due funzioni di estensione con la stessa firma e una di esse si trova nello stesso spazio dei nomi, a quella verrà assegnata una priorità. D'altra parte, se si accede a entrambi using , allora si verificherà un errore di compilazione con il messaggio:

La chiamata è ambigua tra i seguenti metodi o proprietà


Si noti che la convenienza sintattica di chiamare un metodo di estensione tramite originalTypeInstance.ExtensionMethod() è una comodità opzionale. Il metodo può anche essere chiamato nel modo tradizionale, in modo che il primo parametro speciale venga utilizzato come parametro per il metodo.

Vale a dire, entrambi i seguenti lavori:

//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);