Як щодо того, щоб не було ключового слова?
Я хотів би, щоб компілятор усвідомлював, що більшість часу, коли я викликаю асинхронний метод, я хочу, щоб результат його був.
Document doc = DownloadDocumentAsync();
Це воно. Причина, чому люди важко придумують ключове слово для цієї речі, це тому, що це як ключове слово для "робити те, що ти робив би, якби справи були абсолютно нормальними". Це повинно бути за замовчуванням, не вимагати ключового слова.
Оновлення
Спочатку я запропонував компілятору отримати розумний висновок про тип, щоб зрозуміти, що робити. Думаючи далі про це, я б зберег існуючу реалізацію в CTP такою, якою вона є, але внести до неї кілька дрібницьких доповнень, щоб зменшити випадки, коли вам потрібно буде awaitчітко використовувати ключове слово.
Ми винаходимо атрибут: [AutoAwait]. Це можна застосувати лише до методів. Один із способів застосувати це до вашого методу - позначити його async. Але ви також можете це зробити вручну, наприклад:
[AutoAwait]
public Task<Document> DownloadDocumentAsync()
Тоді всередині будь-якого asyncметоду компілятор припустить, що ви хочете чекати на виклик DownloadDocumentAsync, тому не потрібно його вказувати. Будь-який дзвінок до цього методу автоматично його чекає.
Document doc = DownloadDocumentAsync();
Тепер, якщо ви хочете "стати розумним" і отримати його Task<Document>, ви використовуєте оператор start, який може з'явитися лише перед викликом методу:
Task<Document> task = start DownloadDocumentAsync();
Охайний, я думаю. Тепер звичайний виклик методу означає те, що він зазвичай означає: чекайте завершення методу. І startвказує на щось інше: не чекай.
Для коду, який з’являється поза asyncметодом, єдиний спосіб, яким ви можете викликати [AutoAwait]метод, - це префіксація start. Це змушує вас писати код, який має однакове значення незалежно від того, відображається він у asyncметоді чи ні.
Тоді я починаю жадібний! :)
По-перше, я хочу asyncзастосувати методи інтерфейсу:
interface IThing
{
async int GetCount();
}
Це в основному означає, що метод реалізації повинен повернутися Task<int>або щось сумісне з await, і абоненти до методу отримають [AutoAwait]поведінку.
Також коли я реалізую вищевказаний метод, я хочу мати можливість писати:
async int GetCount()
Тому я не повинен згадувати Task<int>як тип повернення.
Також я хочу asyncзвернутися до типів делегатів (які, зрештою, схожі на інтерфейси одного методу). Так:
public async delegate TResult AsyncFunc<TResult>();
asyncДелегат має - ви вже здогадалися - [AutoAwait]поведінка. З asyncметоду ви можете викликати його, і він буде автоматично awaitвідредагований (якщо ви не вирішите його просто start). Так що, якщо ви кажете:
AsyncFunc<Document> getDoc = DownloadDocumentAsync;
Це просто працює. Це не виклик методу. Жодне завдання ще не розпочато - async delegateце не завдання. Це фабрика для виконання завдань. Ви можете сказати:
Document doc = getDoc();
І це почне завдання і чекатиме його закінчення і дасть результат. Або ви можете сказати:
Task<Document> t = start getDoc();
Тож одне місце в цьому місці, де "сантехніка" протікає, це те, що якщо ви хочете зробити делегат asyncметоду, ви повинні знати async delegateтип. Тож замість Funcвас треба сказати AsyncFuncтощо. Хоча одного дня такі речі можуть бути виправлені за допомогою поліпшеного виводу типу.
Інше питання - що має статися, якщо ви скажете почати із звичайного (несинхронного) методу. Очевидно, що помилка компіляції була б безпечним варіантом. Але є й інші можливості.