web-dev-qa-db-fra.com

délégués anonymes en C #

Je ne peux pas être le seul à être fatigué de définir et de nommer un délégué pour un seul appel à quelque chose qui nécessite un délégué. Par exemple, je voulais appeler .Refresh () sous une forme provenant éventuellement d'autres threads, j'ai donc écrit ce code:

private void RefreshForm()
{
    if (InvokeRequired)
        Invoke(new InvokeDelegate(Refresh));
    else
        Refresh();
}

Je ne suis même pas sûr de devoir le faire, j'ai juste lu assez pour avoir peur que ça ne marche pas plus tard.
InvokeDelegate est en fait déclaré dans un autre fichier, mais ai-je vraiment besoin d'un délégué entier dédié juste pour cela? n'y a-t-il pas du tout de délégués génériques?
Je veux dire, par exemple, il y a une classe Pen, mais il y a aussi des stylos. stylo de choix donc vous n'avez pas pour refaire le tout. Ce n'est pas pareil, mais j'espère que vous comprenez ce que je veux dire.

34
Nefzen

Oui. Dans .NET 3.5, vous pouvez utiliser les délégués Func et Action . Les délégués Func renvoient une valeur, tandis que les délégués Action renvoient void. Voici à quoi ressembleraient les noms de types:

System.Func<TReturn> // (no arg, with return value)
System.Func<T, TReturn> // (1 arg, with return value)
System.Func<T1, T2, TReturn> // (2 arg, with return value)
System.Func<T1, T2, T3, TReturn> // (3 arg, with return value)
System.Func<T1, T2, T3, T4, TReturn> // (4 arg, with return value)

System.Action // (no arg, no return value)
System.Action<T> // (1 arg, no return value)
System.Action<T1, T2> // (2 arg, no return value)
System.Action<T1, T2, T3> // (3 arg, no return value)
System.Action<T1, T2, T3, T4> // (4 arg, no return value)

Je ne sais pas pourquoi ils se sont arrêtés à 4 arguments chacun, mais cela a toujours été suffisant pour moi.

52
skb

Il y a le délégué Action que vous pouvez utiliser, comme ceci:

private void RefreshForm()
{
    if (InvokeRequired) Invoke(new Action(Refresh));
    else Refresh();
}

Ou, avec la syntaxe lambda:

private void RefreshForm()
{
    if (InvokeRequired) Invoke((Action)(() => Refresh()));
    else Refresh();
}

Enfin, il existe une syntaxe de délégué anonyme:

private void RefreshForm()
{
    if (InvokeRequired) Invoke((Action)(delegate { Refresh(); }));
    else Refresh();
}
26
Erik Forbes

Dans ce cas spécifique, vous pouvez (et devez) simplement utiliser MethodInvoker pour ce faire ... c'est pourquoi il existe.

if (InvokeRequired)
    Invoke(new MethodInvoker(Refresh));
else
    Refresh();

Si vous faisiez autre chose, vous pourriez, comme d'autres l'ont répondu, utiliser Func <T, ...> ou Action <T, ...> s'ils correspondent à votre cas d'utilisation.

8
Brian ONeil

Version courte:

Invoke((MethodInvoker)delegate { Refresh(); });

Ensuite, vous pouvez également supprimer la vérification d'InvokeRequired; vous pouvez simplement l'appeler tel quel. Fonctionne également si vous devez transmettre des paramètres, il n'est donc pas nécessaire d'avoir d'autres délégués spécifiques aux paramètres (fonctionne aussi bien avec le délégué Action sans paramètres):

private void SetControlText(Control ctl, string text)
{
    Invoke((MethodInvoker)delegate { ctl.Text = text; });
}
5
Fredrik Mörk

Ai-je vraiment besoin d'un délégué entier dédié juste pour ça? n'y a-t-il pas du tout de délégués génériques?

La définition de vos propres délégués peut vraiment faciliter le débogage, ne serait-ce que parce qu'Intellisense peut vous indiquer les noms de vos paramètres. Par exemple, vous écrivez un délégué comme ceci:

public delegate int UpdateDelegate(int userID, string city, string, state, string Zip);

Lorsque vous utilisez ce code, .NET vous informera des noms des paramètres, du nom du délégué, etc., il y a donc beaucoup de contexte dans la définition du délégué si vous n'êtes pas sûr de la façon exacte dont quelque chose est utilisé.

Cependant, si cela ne vous dérange pas de sacrifier Intellisense, il existe déjà une classe de délégués définie dans l'espace de noms System qui peut être utilisée comme délégués ad hoc:

Func<T>
Func<T, U>
Func<T, U, V>
Func<T, U, V, W>
Action, Action<T>
Action<T, U>
Action<T, U, V>
Action<T, U, V, W>

Seuls Action et Action existent dans .NET 2.0, mais il est assez facile de déclarer une classe d'assistance avec les délégués restants dont vous avez besoin pour ce type de fonctions ad hoc diverses.

2
Juliet

Oui, il y a des délégués génériques. Action<T1, T2...> est un délégué générique qui accepte certains paramètres et ne renvoie aucune valeur, et Func<T1, T2...R> est un délégué générique qui prend certains paramètres et renvoie une valeur.

1
mqp