Co powiesz na brak słowa kluczowego?
Chciałbym, aby kompilator zdał sobie sprawę, że przez większość czasu, gdy wywołuję metodę asynchroniczną, chcę jej wynik.
Document doc = DownloadDocumentAsync();
Otóż to. Powodem, dla którego ludzie mają trudności z wymyśleniem słowa kluczowego dla tej rzeczy, jest to, że jest to słowo kluczowe dla „rób to, co zrobiłbyś, gdyby wszystko było całkowicie normalne”. To powinno być domyślne, nie wymagać słowa kluczowego.
Aktualizacja
Początkowo zasugerowałem, że kompilator powinien być sprytny z wnioskami o typ, aby dowiedzieć się, co robić. Zastanawiając się nad tym, chciałbym zachować obecną implementację w CTP w obecnej postaci, ale dodam do niej kilka trywialnych dodatków, aby zmniejszyć liczbę przypadków, w których konieczne byłoby awaitjawne użycie słowa kluczowego.
Wymyślamy atrybut: [AutoAwait]. Można to zastosować tylko do metod. Jednym ze sposobów, aby zastosować to do metody, jest jej oznaczenie async. Ale możesz to również zrobić ręcznie, np .:
[AutoAwait]
public Task<Document> DownloadDocumentAsync()
Następnie w każdej asyncmetodzie kompilator zakłada, że chcesz poczekać na wywołanie DownloadDocumentAsync, więc nie musisz go określać. Każde wywołanie tej metody będzie automatycznie na nią czekało.
Document doc = DownloadDocumentAsync();
Teraz, jeśli chcesz „uzyskać spryt” i uzyskać Task<Document>, użyj operatora start, który może pojawić się tylko przed wywołaniem metody:
Task<Document> task = start DownloadDocumentAsync();
Zgrabnie, tak myślę. Teraz zwykłe wywołanie metody oznacza to, co zwykle oznacza: poczekaj na zakończenie metody. I startwskazuje coś innego: nie czekaj.
W przypadku kodu, który pojawia się poza asyncmetodą, jedynym sposobem na wywołanie [AutoAwait]metody jest przedrostek start. Zmusza to do pisania kodu o tym samym znaczeniu, niezależnie od tego, czy pojawia się w asyncmetodzie, czy nie.
Potem zaczynam być chciwy! :)
Po pierwsze, chcę asynczastosować się do metod interfejsu:
interface IThing
{
async int GetCount();
}
Zasadniczo oznacza to, że metoda implementująca musi zwrócić Task<int>lub coś kompatybilnego await, a osoby wywołujące metodę otrzymają [AutoAwait]zachowanie.
Również po wdrożeniu powyższej metody chcę móc pisać:
async int GetCount()
Więc nie muszę wspominać Task<int>o typie zwrotu.
Chcę asyncrównież zastosować do typów delegowanych (które przecież są jak interfejsy z jedną metodą). Więc:
public async delegate TResult AsyncFunc<TResult>();
asyncDelegat posiada - zgadliście - [AutoAwait]zachowanie. Z asyncmetody możesz ją wywołać, a zostanie ona automatycznie awaitedytowana (chyba że zdecydujesz się to startzrobić). A więc jeśli powiesz:
AsyncFunc<Document> getDoc = DownloadDocumentAsync;
To po prostu działa. To nie jest wywołanie metody. Żadne zadanie nie zostało jeszcze uruchomione - async delegatenie jest zadaniem. To fabryka do wykonywania zadań. Możesz powiedzieć:
Document doc = getDoc();
A to rozpocznie zadanie i zaczekaj, aż się zakończy i da ci wynik. Lub możesz powiedzieć:
Task<Document> t = start getDoc();
Tak więc jednym z miejsc, w których przecieka „hydraulika”, jest to, że jeśli chcesz delegować asyncmetodę, musisz wiedzieć, że używasz async delegatetypu. Zamiast tego Funcmusisz powiedzieć AsyncFunci tak dalej. Chociaż pewnego dnia tego rodzaju rzeczy mogą zostać naprawione przez lepsze wnioskowanie o typie.
Innym pytaniem jest, co powinno się stać, jeśli powiesz, że zacznij od zwykłej metody (nie asynchronicznej). Oczywiście błąd kompilacji byłby bezpieczną opcją. Ale są też inne możliwości.