Que diriez-vous de ne pas avoir de mot-clé?
J'aimerais que le compilateur se rende compte que, la plupart du temps, lorsque j'appelle une méthode asynchrone, je veux le résultat.
Document doc = DownloadDocumentAsync();
C'est ça. La raison pour laquelle les gens ont du mal à trouver un mot-clé pour cette chose est parce que c'est comme avoir un mot-clé pour "faire ce que vous feriez si les choses étaient parfaitement normales". Cela devrait être la valeur par défaut, pas besoin d'un mot clé.
Mise à jour
J'ai suggéré à l'origine que le compilateur devrait être intelligent avec l'inférence de type pour comprendre quoi faire. En réfléchissant davantage à cela, je garderais l'implémentation existante dans le CTP telle qu'elle est, mais j'y ferais quelques ajouts triviaux, afin de réduire les cas où vous auriez besoin d'utiliser le await
mot clé explicitement.
Nous inventons un attribut: [AutoAwait]
. Cela ne peut être appliqué qu'aux méthodes. Une façon de l'appliquer à votre méthode consiste à la marquer async
. Mais vous pouvez également le faire à la main, par exemple:
[AutoAwait]
public Task<Document> DownloadDocumentAsync()
Ensuite, à l'intérieur de n'importe quelle async
méthode, le compilateur supposera que vous voulez attendre un appel à DownloadDocumentAsync
, vous n'avez donc pas besoin de le spécifier. Tout appel à cette méthode l'attendra automatiquement.
Document doc = DownloadDocumentAsync();
Maintenant, si vous voulez "devenir intelligent" et obtenir le Task<Document>
, vous utilisez un opérateur start
, qui ne peut apparaître qu'avant un appel de méthode:
Task<Document> task = start DownloadDocumentAsync();
Bien, je pense. Maintenant, un appel de méthode simple signifie ce qu'il signifie généralement: attendez que la méthode soit terminée. Et start
indique quelque chose de différent: n'attendez pas.
Pour le code qui apparaît en dehors d'une async
méthode, la seule façon dont vous êtes autorisé à appeler une [AutoAwait]
méthode est de la préfixer avec start
. Cela vous oblige à écrire du code qui a la même signification, qu'il apparaisse async
ou non dans une méthode.
Ensuite, je commence à devenir gourmand! :)
Tout d'abord, je souhaite async
appliquer aux méthodes d'interface:
interface IThing
{
async int GetCount();
}
Cela signifie essentiellement que la méthode d'implémentation doit retourner Task<int>
ou quelque chose de compatible avec await
, et les appelants à la méthode obtiendront un [AutoAwait]
comportement.
De plus, lorsque j'implémente la méthode ci-dessus, je veux pouvoir écrire:
async int GetCount()
Je n'ai donc pas à mentionner Task<int>
comme type de retour.
De plus, je veux async
m'appliquer aux types de délégués (qui, après tout, sont comme des interfaces avec une méthode). Donc:
public async delegate TResult AsyncFunc<TResult>();
Un async
délégué a - vous l'aurez deviné - un [AutoAwait]
comportement. À partir d'une async
méthode, vous pouvez l'appeler et elle sera automatiquement await
éditée (à moins que vous ne choisissiez de la juste start
). Et donc si vous dites:
AsyncFunc<Document> getDoc = DownloadDocumentAsync;
Ça marche. Ce n'est pas un appel de méthode. Aucune tâche n'a encore été lancée - une async delegate
n'est pas une tâche. C'est une usine pour faire des tâches. Tu peux dire:
Document doc = getDoc();
Et cela va démarrer une tâche et attendre qu'elle se termine et vous donner le résultat. Ou vous pouvez dire:
Task<Document> t = start getDoc();
Donc, un endroit dans ce domaine où la "plomberie" fuit est que si vous voulez faire un délégué à une async
méthode, vous devez savoir utiliser un async delegate
type. Donc au lieu de Func
vous devez dire AsyncFunc
, et ainsi de suite. Bien qu'un jour ce genre de chose pourrait être corrigé par une inférence de type améliorée.
Une autre question est de savoir ce qui devrait arriver si vous dites commencer par une méthode ordinaire (non asynchrone). De toute évidence, une erreur de compilation serait l'option sûre. Mais il y a d'autres possibilités.