English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Delegato di C# (Delegate)

Se vogliamo passare una funzione come parametro come si fa? Come gestisce C# le funzioni di callback o gli eventi di gestione? La risposta è - delegato (Delegate). Un delegato (Delegate) è un tipo di variabile di riferimento che contiene un riferimento a un metodo. Il riferimento può essere modificato in tempo di esecuzione.

Il delegato èDefinire la firma del metodoil tipo di dati di riferimento. È possibile definire una variabile di delegato, come altri tipi di dati, che può riferirsi a qualsiasi metodo con la firma corrispondente al delegato.

Lavorare con i delegati implica tre passaggi:

  1. Dichiarazione del delegato

  2. Impostare il metodo di destinazione

  3. Chiamata del delegato

È possibile dichiarare un delegato utilizzando la parola chiave delegate e la firma della funzione, come mostrato di seguito.

  Sintassi del delegato

[modificatore di accesso] delegate [tipo di ritorno] [nome del delegato]([parametri])

Ecco una dichiarazione di un delegato chiamato MyDelegate.

public delegate void MyDelegate(string msg);

Sopra, abbiamo dichiarato un MyDelegate convoidTipo di ritorno e parametro di stringa. È possibile dichiarare il delegato sia all'interno che all'esterno della classe. In realtà, dovrebbe essere dichiarato all'esterno della classe.

Dopo aver dichiarato il delegato, dobbiamo impostare il metodo di destinazione o l'espressione lambda. Possiamo farlo creando un oggetto del delegato utilizzando la parola chiave new e passando un metodo che ha la firma corrispondente al delegato.

public delegate void MyDelegate(string msg); // dichiarazione del delegato
//impostare il metodo di destinazione
MyDelegate del = new MyDelegate(MethodA);
// o
MyDelegate del = MethodA; 
// o espressione lambda 
MyDelegate del = (string msg) => Console.WriteLine(msg);
// metodo di destinazione
static void MethodA(string message)
{
    Console.WriteLine(message);
}

È possibile impostare il metodo di destinazione direttamente assegnando un metodo senza creare un oggetto del delegato, ad esempio MyDelegate del = MethodA.

Dopo aver impostato il metodo di destinazione, è possibile chiamare il delegato utilizzando il metodo Invoke() o l'operatore ().

del.Invoke("Hello World!");
//oppure 
del("Hello World!");

Ecco un esempio completo di delegato.

public delegate void MyDelegate(string msg); // Dichiarazione del delegato
class Program
{
    static void Main(string[] args)
    {
        MyDelegate del = ClassA.MethodA;
        del("Hello World");
        del = ClassB.MethodB;
        del("Hello World");
        del = (string msg) => Console.WriteLine("Chiamato espressione lambda: " + msg);
        del("Hello World");
    }
}
class ClassA
{
    static void MethodA(string message)
    {
        Console.WriteLine("Chiamato ClassA.MethodA() con parametro: " + message);
    }
}
class ClassB
{
    static void MethodB(string message)
    {
        Console.WriteLine("Chiamato ClassB.MethodB() con parametro: " + message);
    }
}

La seguente figura illustra il delegato.

Delegato C#

Passare un delegato come parametro

Il metodo può avere un parametro di tipo delegato, come mostrato di seguito.

public delegate void MyDelegate(string msg); // Dichiarazione del delegato
class Program
{
    static void Main(string[] args)
    {
        MyDelegate del = ClassA.MethodA;
        InvokeDelegate(del);
        del = ClassB.MethodB;
        InvokeDelegate(del);
        del = (string msg) => Console.WriteLine("Chiamato espressione lambda: " + msg);
        InvokeDelegate(del);
    }
    static void InvokeDelegate(MyDelegate del) // Parametro di tipo MyDelegate
    {
        del("Hello World");
    }
}
class ClassA
{
    static void MethodA(string message)
    {
        Console.WriteLine("Chiamato ClassA.MethodA() con parametro: " + message);
    }
}
class ClassB
{
    static void MethodB(string message)
    {
        Console.WriteLine("Chiamato ClassB.MethodB() con parametro: " + message);
    }
}

In .NET, i tipi Func e Action sono delegati generici integrati, che dovrebbero essere utilizzati per i delegati più comuni, piuttosto che creare delegati personalizzati.

Delegato multicast

I delegati possono puntare a più metodi. Un delegato che punta a più metodi viene chiamato delegato multicast. Gli operatori “+” o “+=” aggiungono la funzione alla lista delle chiamate, mentre gli operatori “-” e “-=” la rimuovono.

public delegate void MyDelegate(string msg); // Dichiarazione del delegato
class Program
{
    static void Main(string[] args)
    {
        MyDelegate del1 = ClassA.MethodA;
        MyDelegate del2 = ClassB.MethodB;
        MyDelegate del = del1 + del2; // del1 + del2
        del("Hello World");
        MyDelegate del3 = (string msg) => Console.WriteLine("Chiamato espressione lambda: " + msg);
        del += del3; // del1 + del2 + del3
        del("Hello World");
        del = del - del2; // Rimuovi del2
        del("Hello World");
        del -= del1 // Rimuovi del1
        del("Hello World");
    }
}
class ClassA
{
    static void MethodA(string message)
    {
        Console.WriteLine("Chiamato ClassA.MethodA() con parametro: " + message);
    }
}
class ClassB
{
    static void MethodB(string message)
    {
        Console.WriteLine("Chiamato ClassB.MethodB() con parametro: " + message);
    }
}

Gli operatori di somma e sottrazione lavorano sempre come parte dell'assegnazione: del1 += del2; è completamente equivalente a del1 = del1 + del2; la sottrazione è la stessa.

Se il delegato restituisce un valore, allora quando viene chiamato un delegato multicast, il valore dell'ultimo metodo di destinazione assegnato viene restituito.

public delegate int MyDelegate(); // dichiarazione del delegato
class Program
{
    static void Main(string[] args)
    {
        MyDelegate del1 = ClassA.MethodA;
        MyDelegate del2 = ClassB.MethodB;
        MyDelegate del = del1 + del2; 
        Console.WriteLine(del()); // restituisce 200
    }
}
class ClassA
{
    static int MethodA()
    {
        return 100;
    }
}
class ClassB
{
    static int MethodB()
    {
        return 200;
    }
}

Delegato generico

Puoi definire un delegato generico nello stesso modo di un delegato, ma puoi utilizzare i parametri di tipo generico o il tipo di ritorno. Quando si imposta il metodo di destinazione, è necessario specificare il tipo generico.

Ad esempio, guardiamo il delegato generico utilizzato per i parametri int e string.

public delegate T add<T>(T param1, T param2); // delegato generico
class Program
{
    static void Main(string[] args)
    {
        add<int> sum = Sum;
        Console.WriteLine(sum(10, 20));
        add<string> con = Concat;
        Console.WriteLine(conct("Hello ", "World!!"));
    }
    public static int Sum(int val1, int val2)
    {
        return val1 + val2;
    }
    public static string Concat(string str1, string str2)
    {
        return str1 + str2;
    }
}

I delegati sono anche utilizzati per dichiarare eventi e metodi anonimi.

 Punti da ricordare

  1. Un delegato è un tipo di dati di riferimento che definisce una firma.

  2. Un variabile di tipo delegato può riferirsi a qualsiasi metodo con lo stesso nome di firma del delegato.

  3. Sintassi:[访问修饰符] delegato [return type] [delegate name]([参数])([access modifier] delegate [return type] [delegate name]([parameters]))

  4. La firma del metodo di destinazione deve corrispondere alla firma del delegato.

  5. Il delegato può essere chiamato come una funzione comune o tramite il metodo invoke().

  6. È possibile assegnare più metodi a un delegato utilizzando l'operatore “+” o “+=” e rimuoverli utilizzando l'operatore “-” o “-=”; questo viene chiamato delegato multicast.

  7. Se un delegato multicast restituisce un valore, restituisce il valore dell'ultimo metodo target assegnato.

  8. Il delegato viene utilizzato per dichiarare eventi e metodi anonimi in C#.