web-dev-qa-db-fra.com

Quelle est la signature de méthode pour passer un délégué asynchrone?

Je suis récemment revenu en C # après avoir été en terre Objective-C, et les mots-clés asynchrones/attendent en C # 5 ont l'air cool. Mais j'essaie toujours de comprendre la syntaxe appropriée.

Je veux déclarer une méthode qui prend un délégué asynchrone comme paramètre, mais j'ai du mal à obtenir à la fois l'appelant et la syntaxe de l'appelé correct. Quelqu'un peut-il fournir un exemple de code montrant la déclaration de méthode, l'appel et un appel au délégué?

Je pense que la déclaration serait quelque chose comme ce qui suit. Notez que cette fonction n'est pas asynchrone; c'est-à-dire que son asynchronicité est indépendante du délégué.

void DoSomethingWithCallback(async delegate foo(int)) 
{
    ...
    foo(42);
    ...
}

L'appel serait quelque chose comme:

DoSomethingWithCallback(async (int x) => { this.SomeProperty = await SomeAsync(x); });

Bien sûr, rien de tout cela ne se compile et la plupart des exemples que j'ai vus supposent que l'un a un champ ou une propriété qui est le délégué, plutôt que le délégué anonyme que j'aimerais utiliser.

47
AndrewS

Une fonction qui prend un délégué comme paramètre doit utiliser un type de délégué nommé; contrairement à Objective-C, vous ne pouvez pas déclarer un type de délégué anonyme en ligne dans la définition de la fonction. Cependant, les génériques Action <> et Func <> sont fournis afin que vous n'ayez pas à déclarer vous-même un nouveau type. Dans le code ci-dessous, je suppose que le délégué prend un seul int comme paramètre.

void DoSomethingWithCallback(Func<int,Task> callbackDelegate)
{
    Task t = callbackDelegate(42);
}

Si cette fonction ne en fait fait rien avec l'objet Task retourné (comme avec le code ci-dessus), vous pouvez utiliser à la place Action<int> comme type de délégué. Si vous utilisez Action, vous pouvez toujours déclarer le délégué asynchrone (ci-dessous) mais l'objet de tâche implicite renvoyé est ignoré.

La syntaxe lambda pour appeler la fonction ci-dessus est simple et la syntaxe que vous avez utilisée dans la question est correcte. Notez que le type de paramètre n'a pas besoin d'être spécifié ici car il peut être déduit:

DoSomethingWithCallback(async (intParam) => { this.myint = await Int2IntAsync(intParam); });

Vous pouvez également passer une méthode ou une variable déléguée, si vous le souhaitez, au lieu d'utiliser la syntaxe lambda:

async Task MyInt2Int(int p) { ... }
Func<int,Task> myDelegate;
void OtherMethod()
{
    myDelegate = MyInt2Int;
    DoSomethingWithCallback(myDelegate); // this ...
    DoSomethingWithCallback(MyInt2Int);  // ... or this.
}
61
AndrewS

Le type de retour de la méthode signatue est Task s'il n'y a pas de type de retour, ou Task<T> s'il existe un type de retour.

Tho, je ne suis pas certain à 100% si vous pouvez avoir des lambdas asynchrones comme ça.

Dans la méthode qui consomme la tâche, vous devez soit "attendre" la tâche, soit utiliser les propriétés et méthodes de la tâche pour obtenir le résultat.

5
John Gietzen