Чи залежить використання суфікса "Async" у назві методу від того, чи використовується модифікатор "async"?


106

Яка умова для назви методів суфіксації за допомогою "Async"?

Чи слід додавати суфікс "Async" лише до методу, який оголошується asyncмодифікатором?

public async Task<bool> ConnectAsync()

Або достатньо, щоб метод просто повертався Task<T>або Task?

public Task<bool> ConnectAsync()

4
У частині іменування, документ TAP говорить: Асинхронні методи в TAP включають суфікс Async після імені операції; наприклад, GetAsync для операції get. Якщо ви додаєте метод TAP до класу, який вже містить ім'я цього методу за допомогою суфікса Async, використовуйте замість нього суфікс TaskAsync. Наприклад, якщо в класі вже є метод GetAsync, використовуйте ім'я GetTaskAsync.
Джеймс Меннінг

4
ок, я думаю, мене збентежила назва питання "Конвенція іменування методів асинхронізації"
Джеймс Меннінг

1
Це погано побудоване питання. Люди б’ються, однозначні відповіді.
Люк Пуплетт

4
Тому що багато людей неправильно зрозуміли це і сперечаються щодо фактичного запитуваного питання, цікавлячись, чи це двоскладове запитання тощо. Доказом того, що його плутають, є те, що люди плутаються.
Люк Пуплетт

2
@DavidRR На сьогоднішній день я досі не розумію сумніву плутанини, яку, мабуть, викликало це питання. Якщо ваші редагування наводять певний порядок в замішанні таким чином, що це допомогло вам і, можливо, може допомогти іншим, тоді я вітаю ваші зміни, оскільки ви досягли чогось, чого я не міг у первісному формулюванні. Питання зараз настільки давнє, що я навряд чи пригадую свою думку, коли я його тут задав, і тому початковий намір менш важливий. Відповідь Луки відображає, що не всі були розгублені. Я вважаю це надзвичайно корисним.
kasperhj

Відповіді:


127

Я думаю, що правда неоднозначна навіть з документації Microsoft:

У Visual Studio 2012 та .NET Framework 4.5 будь-який метод, який приписується asyncключовому слову ( Asyncу Visual Basic), вважається асинхронним методом, і компілятори C # і Visual Basic виконують необхідні перетворення для реалізації методу асинхронно за допомогою TAP. Асинхронний метод повинен повертати Taskабо Task<TResult>об’єкт.

http://msdn.microsoft.com/en-us/library/hh873177(v=vs.110).aspx

Це вже не правильно. Будь-який метод з asyncасинхронним, і тоді, за його словами, він повинен повертати Taskабо Task<T>-, що не підходить для методів у верхній частині стека викликів, наприклад Button_Click, або async void.

Звичайно, ви повинні врахувати, який сенс конвенції?

Можна сказати, що Asyncумова суфікса полягає в тому, щоб повідомити користувачеві API про те, що метод очікується. Щоб метод був очікуваним, він повинен повернутися Taskдля недійсності або Task<T>для методу повернення значення, а це означає, що лише останній може мати суфікс Async.

Або ви можете сказати, що Asyncумова суфікса полягає в повідомленні про те, що метод може повернутися негайно, відмовившись від поточного потоку для виконання інших робіт і, можливо, спричинивши перегони.

Ця цитата Microsoft doc говорить:

За умовою ви додаєте "Async" до імен методів, які мають модифікатор Async або async.

http://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_NamingConvention

Що навіть не згадує, що для власних асинхронних методів повернення Taskпотрібен Asyncсуфікс, що, на мою думку, ми всі згодні.


Тож відповідь на це питання могла бути: і те, і інше. В обох випадках вам потрібно додати Asyncметоди з asyncключовим словом і повернути Taskабо Task<T>.


Я попрошу Стівена Туба прояснити ситуацію.

Оновлення

Так я і зробив. А ось що написав наш добрий чоловік:

Якщо загальнодоступний метод є поверненням завдань і має асинхронний характер (на відміну від методу, який, як відомо, завжди виконується синхронно до завершення, але все-таки повертає Завдання з якоїсь причини), він повинен мати суфікс "Асинхронізація". Ось такий настанов. Основна мета тут при іменуванні - зробити його очевидним для споживача функціональності, що метод, який використовується, швидше за все, не завершить всю свою роботу синхронно; це, звичайно, також допомагає у випадку, коли функціональність піддається як синхронним, так і асинхронним методам таким чином, що вам потрібна різниця імен для їх розрізнення. Те, як метод досягає своєї асинхронної реалізації, не має значення для іменування: чи використовується async / await для отримання допомоги компілятора, чи використовуються типи та методи з System.Threading.Tasks безпосередньо (наприклад, г. TaskCompletionSource) насправді не має значення, оскільки це не впливає на підпис методу, що стосується споживача методу.

Звичайно, завжди є винятки з настанови. Найбільш помітним у випадку іменування були б випадки, коли raison d'etre цілого типу - це надання функціоналу, орієнтованого на асинхронізацію, і в цьому випадку, якщо матиме Async на кожному методі, було б надмірним, наприклад, методами самої задачі, які виробляють інші завдання .

Що стосується асинхронних методів, що повертаються до недійсності, не бажано, щоб вони були на публічній поверхні, оскільки абонент не має хорошого способу знати, коли асинхронна робота завершена. Якщо ви повинні відкрити асинхронний метод, що повертається до недійсності, публічно, ви, ймовірно, хочете мати ім’я, яке передає, що асинхронна робота ініціюється, і ви можете використовувати суфікс "Асинхроніка" тут, якщо це має сенс. З огляду на те, наскільки рідкісним має бути цей випадок, я можу стверджувати, що це дійсно конкретні рішення.

Я сподіваюся, що це допоможе, Стів

Короткий вказівник із вступного речення Стівена досить чіткий. Це виключає, async voidоскільки незвично бажати створювати публічний API з таким дизайном, оскільки правильним способом реалізації асинхронної пустоти є повернення простого Taskекземпляра та дозволення компілятору до його магії. Однак якщо ви цього хотіли public async void, Asyncрекомендується додавати . Інші async voidметоди топ-стека, такі як обробники подій, зазвичай не є загальнодоступними і не мають значення / не відповідають умовам.

Для мене це говорить про те, що якщо мені здається, що я задаюся питанням про суфікс Asyncна async void, я, мабуть, повинен перетворити його на async Taskте, щоб абоненти могли його чекати, а потім додати Async.


20
Ну прикро, що у нас немає перевірки часу складання викликів методів. Якщо я називаю метод Get або GetAsync і не використовую очікування з боку виклику, компіляція не вдасться створити. Тож ця умова є СИЛЬНОЮ і дійсно суперечить багатьом рекомендаціям стилю Microsoft, як, наприклад, уникнення таких речей, як-то PersonStringчи PriceDecimalнавіщо це використовувати GetAsync- споживачам API програми async API не потрібно хвилюватися з цього приводу, оскільки запит завжди повертається після завершення всіх завдань. Це нерозумно і справді мене дратує. Але це ще одна умова, про яку ніхто насправді не знає, чому її існує.
Петро Кула

2
@ppumkin: Як зазначив Стівен, метод може бути легко асинхронним за своєю природою без використання асинхронізування / очікування, таким чином, у абонента немає жодної вказівки, окрім назви, чи функціональність працює асинхронно.
Ханнобо

6
@ppumkin: Якщо не чекати методу асинхронізації, за замовчуванням призводить попередження часу компіляції; не помилка побудови.
Дастін Клівленд

7
Я вважаю цю умову дурною. Існує три автоматичні індикації того, що метод є асинхронним: 1. Тип повернення - Завдання. 2. Завершення коду представляє очікуваний підказку 3. IDE попередить вас, підкресливши зеленим кольором та представивши попередження компілятора. Тож я повністю згоден з @ppumkin. Суфікс Async такий же нерозумний, як ніби ви написали таке властивість: public Lazy <Customer> CustomerLazy. Хто б це зробив! ??
Марко

2
@Marco Я підняв цю ідею на GitHub, подумав, що це найкраще місце, але не маю стосунків
Люк Пуплетт

68

Я будую багато API-сервісів та інших програм, які викликають інші системи, де більшість мого коду працює асинхронно.

Моє власне правило:

Якщо є і не-асинхронний, і асинхронний метод, які повертають одне і те ж, я суфіксую асинхронний з Асинхронним. Інакше ні.

Приклади:

Лише один метод:

public async Task<User> GetUser() { [...] }

Той самий метод з двома підписами:

public User GetUser() { [...] }

public async Task<User> GetUserAsync() { [...] }

Це має сенс, оскільки це ті самі дані, які повертаються, але єдине, що відрізняється - це спосіб повернення даних , а не самі дані.

Я також думаю, що ця умова про іменування існує через необхідність впроваджувати методи асинхронізації та все ще підтримувати сумісність у зворотному напрямку.

Я стверджую, що новий код не повинен використовувати суфікс Async. Це так само очевидно, як і тип повернення String, або Int, як згадувалося раніше в цій темі.


8
Я погоджуюсь, особливо, що зазвичай потрібно пройти "асинхронізувати весь шлях", і в цьому випадку суфікс є зайвим - який сенс додавати його до 90% коду;)
Bartosz

3
це найкраще рішення. Не помічаючи цього, я працював так само в своїх API.
Марко

2
Це набагато краще, ніж суфікс із "Асинхроністом" усіх методів застосування асинхронізу
Маріуш Джамро

Проблема цієї методики полягає в тому, що якщо пізніше створити несинхронну версію, ви не зможете використовувати вподобане ім’я "GetUser ()".
Девід

3
Це прагматичний шлях. Додавання Async до кожного методу, який має модифікатор асинхронізації, є лише угорською нотацією 2019. @David, якщо ви в кінцевому підсумку додаєте не-асинхронну версію пізніше, то перейменуйте методи та дотримуйтесь конвенції іменування або просто не робіть цього.
Скримслі

25

Яка умова щодо суфіксації назв методів з "Async".

В основі завдань Asynchronous Pattern (TAP) диктує , що методи завжди повинні повертати Task<T>(або Task) і бути названі з асинхронним суфіксом; це окремо від використання async. І те, Task<bool> Connect()і компілюватимуться та запускатимуться добре, але ви не будете дотримуватися конвенції про іменування TAP.asyncTask<bool> Connect()

Чи повинен метод містити asyncмодифікатор або його достатньо, щоб він просто повертав завдання?

Якщо тіло методу (незалежно від типу повернення чи назви) включає await, ви повинні використовувати async; і компілятор скаже вам "Оператор" очікування "можна використовувати лише в методі асинхронізації. ...". Повернення Task<T>або Taskнедостатньо ", щоб уникнути використання async. Докладніше див. У розділі async (C # Reference) .

Тобто, які з цих підписів є правильними:

Обидва і належним чином дотримуються конвенцій TAP. Ви завжди можете використовувати ключове слово, але ви отримаєте попередження компілятора "У цього методу асинхронізації немає операторів" очікування "і запуститься синхронно. ...", якщо тіло не використовує .asyncTask<bool> ConnectAsync()Task<bool> ConnectAsync()asyncawait


1
Він посилається на те, додаєте ви "Асинхронізацію" до назви методу чи ні, не використовуєте ви asyncключове слово.
Сервіс

1
@ Сервіс, якщо це не використовується або не використовується ключове слово, asyncє другою частиною питання.
Корак

2
@ Сервіс Це питання з двох частин. Перша частина, як ви сказали, - додавати чи ні додати назву методу "Async". Друга частина - використовувати чи не використовувати asyncмодифікатор. Дивіться також приклади ОП, public async Task<bool> ConnectAsync()asyncмодифікатором) проти public Task<bool> ConnectAsync()(без asyncмодифікатора). Метод назва має суфікс "Async" в обох випадках.
Корак

2
Це питання не з двох частин. Питання в тому, чи слід "Async" додавати до імен методів, які повертаються, Taskабо методів, які є async Task.
kasperhj

3
@lejon: вам слід покращити питання; "проти" фрагменти коду дають зрозуміти, що питання (у повному обсязі) про асинхронізацію, оскільки це єдина різниця.
Ðаn

11

чи достатньо, щоб він просто повертав Завдання?

Це. asyncКлючове слово не є реальною проблемою тут. Якщо ви реалізуєте асинхронію без використання asyncключового слова, метод все ще є "Асинхронністю", у загальному розумінні.


7

Так Taskі Task<T>обидва awaitable типу, вони представляють собою деякі асинхронні операції. Або принаймні вони повинні представляти.

Ви повинні додати суфікс Asyncдо методу, який у деяких випадках (не обов'язково всі) не повертає значення, а повертає обгортку навколо поточної операції. Ця обгортка зазвичай є Task, але на Windows RT це може бути IAsyncInfo. Слідкуйте за своїм відчуттям кишки і пам’ятайте, що якщо користувач вашого коду бачить цю Asyncфункцію, він або вона буде знати, що виклик цього методу від'єднується від результату цього методу, і їм потрібно діяти відповідно.

Зауважте, що існують такі методи, як Task.Delayі Task.WhenAllякі повертаються, Taskале Asyncсуфікс ще не має .

Також зауважте, що існують async voidметоди, що представляють собою асинхронний метод запускання та забуття, і вам слід краще знати, що метод побудований таким чином.


6

Я б заперечував, що він повинен використовувати суфікс Async, якщо він повертає завдання, незалежно від того, задекларований метод з asyncмодифікатором чи ні.

Причина тому, що ім'я оголошено в інтерфейсі. Інтерфейс оголошує тип повернення, який є a Task. Тоді є дві реалізації цього інтерфейсу, одна реалізація реалізує його за допомогою asyncмодифікатора, інша - ні.

public interface IFoo
{
    Task FooAsync();
}

public class FooA : IFoo
{
    public Task FooAsync() { /* ... */ }
}

public class FooB : IFoo
{
    public async Task FooAsync() { /* ... */ }
}

Це так правда. Ми завжди використовуємо інтерфейси скрізь, і інтерфейси не можна оголосити асинхронними. Тож офіційні вказівки щодо використання суфікса Async мені здаються абсолютно нісенітницею. Я думаю, що ключове слово async - це лише детальна інформація про реалізацію, частина внутрішніх методів, і не повинна впливати на його назву чи будь-які зовнішні.
Al Kepp

5

У асинхронному програмуванні за допомогою асинхронізації та очікування (C #) Microsoft пропонує такі вказівки:

Конвенція про іменування

За домовленістю ви додаєте "Async" до назв методів, які мають асинхронізацію модифікатор .

Ви можете ігнорувати конвенцію, коли подія, базовий клас або інтерфейсний договір пропонують іншу назву. Наприклад, не слід перейменовувати поширені обробники подій, такі як Button1_Click.

Я вважаю це керівництво неповним і незадовільним. Чи означає це, що за відсутності asyncмодифікатора цей метод слід називати Connectзамість ConnectAsync?

public Task<bool> ConnectAsync()
{
    return ConnectAsyncInternal();
}

Я не думаю, що так. Як зазначено в короткому відповіді по @Servy і більш докладну відповідь по @Luke Puplett , я вважаю , що це доречно і в самому справі очікувати , що цей метод повинен бути названий ConnectAsync(бо вона повертає awaitable). Надалі підтверджуючи це, @John Skeet у цій відповіді на інше запитання додає Asyncназву методу незалежно від наявності asyncмодифікатора.

Нарешті, з іншого питання , розгляньте цей коментар від @Damien_The_Unbeliever :

async/awaitє впровадження деталі ваших методів. Не має значення жодна йота, чи оголошено ваш метод async Task Method()чи просто Task Method(), що стосується ваших абонентів . (Насправді ви можете вільно змінюватись між цими двома в більш пізній момент часу, не вважаючи це переломною зміною.)

З цього я роблю висновок, що саме асинхронний характер методу диктує, як його слід назвати. Користувач методу навіть не дізнається, чи використовується asyncмодифікатор при його реалізації (без вихідного коду C # або CIL).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.