Condividi tramite


Delegate con tipi fortemente definiti

Precedente

Nell'articolo precedente è stato illustrato come creare tipi delegati specifici usando la delegate parola chiave .

La classe delegate astratta fornisce l'infrastruttura per l'accoppiamento libero e la chiamata. I tipi di delegati concreti diventano molto più utili abbracciando e applicando la sicurezza dei tipi per i metodi che vengono aggiunti alla lista delle invocazioni per un oggetto delegato. Quando si usa la delegate parola chiave e si definisce un tipo delegato concreto, il compilatore genera tali metodi.

In pratica, ciò comporta la creazione di nuovi tipi di delegato ogni volta che è necessaria una firma del metodo diversa. Questo lavoro potrebbe diventare noioso dopo un tempo. Ogni nuova funzionalità richiede nuovi tipi di delegato.

Per fortuna, questo non è necessario. .NET Core Framework contiene diversi tipi che è possibile riutilizzare ogni volta che sono necessari tipi delegati. Si tratta di definizioni generiche che consentono di dichiarare personalizzazioni quando sono necessarie nuove dichiarazioni di metodo.

Il primo di questi tipi è il Action tipo e diverse varianti:

public delegate void Action();
public delegate void Action<in T>(T arg);
public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2);
// Other variations removed for brevity.

Il in modificatore sull'argomento di tipo generico è trattato nell'articolo sulla covarianza.

Esistono varianti del Action delegato che contengono fino a 16 argomenti, Action<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16>ad esempio . È importante che queste definizioni usino argomenti generici diversi per ogni argomento delegato: ciò offre la massima flessibilità. Gli argomenti del metodo non devono essere, ma possono essere, lo stesso tipo.

Usare uno dei tipi Action per qualsiasi tipo di delegato che abbia un tipo di ritorno void.

Il framework include anche diversi tipi di delegato generici che è possibile usare per i tipi delegati che restituiscono valori:

public delegate TResult Func<out TResult>();
public delegate TResult Func<in T1, out TResult>(T1 arg);
public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
// Other variations removed for brevity

Il out modificatore nell'argomento del tipo generico del risultato è trattato nell'articolo sulla covarianza.

Esistono varianti del Func delegato, ad esempio con un massimo di 16 argomenti di input, come Func<T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,T15,T16,TResult>. Il tipo del risultato è sempre l'ultimo parametro di tipo in tutte le Func dichiarazioni, per convenzione.

Usare uno dei Func tipi per qualsiasi tipo delegato che restituisce un valore.

Esiste anche un tipo specializzato Predicate<T> per un delegato che restituisce un test su un singolo valore:

public delegate bool Predicate<in T>(T obj);

È possibile notare che per qualsiasi Predicate tipo esiste un tipo strutturalmente equivalente Func , ad esempio:

Func<string, bool> TestForString;
Predicate<string> AnotherTestForString;

Si potrebbe pensare che questi due tipi siano equivalenti. Non lo sono. Queste due variabili non possono essere usate in modo intercambiabile. Non è possibile assegnare una variabile di un tipo all'altro tipo. Il sistema di tipi C# usa i nomi dei tipi definiti, non la struttura.

Tutte queste definizioni di tipo delegato nella libreria .NET Core devono significare che non è necessario definire un nuovo tipo delegato per una nuova funzionalità creata che richiede delegati. Queste definizioni generiche dovrebbero fornire tutti i tipi di delegati necessari nella maggior parte delle situazioni. È sufficiente creare un'istanza di uno di questi tipi con i parametri di tipo richiesti. Nel caso di algoritmi che possono essere resi generici, questi delegati possono essere usati come tipi generici.

Questo dovrebbe risparmiare tempo e ridurre al minimo il numero di nuovi tipi che è necessario creare per lavorare con i delegati.

Nell'articolo successivo verranno presentati diversi modelli comuni per lavorare con i delegati in pratica.

Avanti