Чи існує остаточна умова іменування методів повернення IAsyncEnumerable?


10

Після того, як C # 5 представила asyncта awaitмодель для асинхронного програмування, спільнота C # придумала конвенцію про іменування, щоб додати суфікс "Async" до методів повернення очікуваного типу, як-от:

interface Foo
{
   Task BarAsync();
}

Багато аналізаторів статичного коду (як на основі Росліна, так і не на основі Росліна) були написані, щоб залежати від цього правила іменування при виявленні запаху коду навколо асинхронного програмування.

Тепер, коли C # 8 ввів концепцію асинхронних перелічених даних, які самі по собі не є очікуваними, але можуть використовуватися спільно з await foreach, мабуть, існує два варіанти повернення методів іменування IAsyncEnumerable:

interface Foo
{
    // No "Async" suffix, indicating that the return value is not awaitable.
    IAsyncEnumerable<T> Bar<T>();
}

або

interface Foo
{
    // With "Async" suffix, indicating that the overall logic is asynchronous.
    IAsyncEnumerable<T> BarAsync<T>();
}

Чи існував остаточний настанов щодо конвенції про іменування (від мовної команди C #, фонду .NET Foundation чи інших органів) стосовно вищезазначених варіантів, як, наприклад, як конвенція про іменування C # 5 була однозначно стандартизована та не залишалася на судженнях програмістів на основі думки?


2
Варіант 2 тут звучить правильно, оскільки ви запускаєте цей код асинхронно (метод позначення як asyncі використовується awaitвсередині), а зразок
msdn

1
У відповідь на закриття запитання я відредагував питання, щоб запитати, чи існує остаточна конвенція іменування, і щоб навести приклад того, як остаточна конвенція іменування в C # 5 призвела до розвитку статичного аналізу коду. Тому, якщо C # 8 дотримується цієї схеми, це призведе до покращуваних показників поліпшення якості коду, що перевищує переваги кодування на основі думки.
hwaien

Сам .NET Core використовує Asyncсуфікс для методів, що повертаються IAsyncEnumerable, наприклад, ChannelReader.ReadAllAsync . В інших випадках, наприклад, в EF Core, AsAsyncEnumerable()використовується вже зрозуміло
Panagiotis Kanavos

Існують вказівки щодо найменування, щоб полегшити людину розуміння коду. Якщо призначення коду не зрозуміло, додайте суфікс.
Панайотис Канавос

Відповіді:


1

Немає кращого керівництва, ніж те, що вже роблять команди .NET :

  • ChannelReader.ReadAllAsync повертаєIAsyncEnumerable<T>
  • У EF Core 3 результати повертаються як IAsyncEnumerableвиклик AsAsyncEnumerable ()
  • У System.Linq.Async ToAsyncEnumerable () перетворює IENumrablesbles, Tasks and Observables у IAsyncEnumerables
  • Усі інші оператори System.Linq.Asyncзберігають свої назви. Немає SelectAsyncабо SelectAsAsyncEnumerable, просто Select.

У всіх випадках зрозуміло, який результат методу. У всіх випадках результатів методу потрібно чекати, await foreachперш ніж їх можна використовувати.

Тож справжнє керівництво залишається тим самим - переконайтеся, що ім’я чітко пояснює поведінку :

  • Коли ім’я вже зрозуміло, наприклад, з AsAsyncEnumerable()або ToAsyncEnumerable(), немає потреби додавати суфікс.
  • В інших випадках додайте Asyncсуфікс, щоб розробники знали, що їм потрібен await foreachрезультат.

Аналізатори коду та генератори насправді не хвилюються назви методів, вони виявляють запахи, перевіряючи сам код. Аналізатор коду покаже вам , що ви забули не чекати Завдання або незалежно від того , як ви називаєте методи і змінні. Генератор може просто використовувати відображення для перевірки та випромінюванняawait foreachIAsyncEnumerableIAsyncEnumerableawait foreach

Саме аналізатори стилів перевіряють назви. Їх завдання полягає в тому, щоб код використовував послідовний стиль, щоб розробники могли зрозуміти код. Аналізатор стилів скаже вам, що метод не відповідає обраному вами стилю. Цей стиль може бути керівництвом команди або загальноприйнятим посібником зі стилів.

І звичайно, всі знають, що загальний префікс для приватних полів екземплярів: _:)


Дякую, що вказали на ChannelReader.ReadAllAsyncприкладі. Оскільки це безпосередньо від команди .NET, важко помилитися в наступному випадку.
hwaien

Пакети аналізаторів часто поставляються з мішком стилю та нестильовими аналізаторами. Наприклад, пакет Microsoft.VisualStudio.Threading.Analyzers має аналізатор стилів, який перевіряє конвенцію іменування (VSTHRD200), і нетиповий аналізатор, який виявляє небезпечні ситуації, які потенційно можуть призвести до тупикової ситуації (VSTHRD111). Для посилання на пакет, щоб скористатися VSTHRD111, проект також закінчився б VSTHRD200.
hwaien

2

Це не метод асинхронізації, тому ім'я не повинно закінчуватися "Async". Цей суфікс методу є умовою, щоб зробити очевидним, що методу слід чекати або результат обробляти як завдання.

Я думаю, що нормальна назва, що повертає колекцію, доречна. GetFoos () або подібне.


Все це аргументи для використання Asyncсуфікса. Суфікс використовується в самому .NET Core: ChannelReader.ReadAllAsync повертає IAsyncEnumerable. Потрібно IAsyncEnumerableвикористовувати з await foreach, тому суфікс має сенс.
Панайотис Канавос

1

Суфікс Async і навіть ключове слово async- це лише плитка, це безглуздо, крім деяких аргументів зворотної порівняльності. C # має всю інформацію для розрізнення цих функцій так само, як це відрізняє yieldу методах, які повертаються IEnumerable, оскільки ви знаєте, що вам не потрібно додавати нічого подібного enumerableабо іншого ключового слова до таких методів.

Суфікс Async потрібно додати лише тому, що C # буде скаржитися на перевантаження, тому по суті ці два ідентичні, і вони роблять те саме за всіма правилами поліморфізму (якщо ми не беремо до уваги людський фактор навмисно корупціонерної поведінки):

public interface IMyContract
{
    Task<int> Add(int a, int b);
    int Add(int a, int b);
}

Але ви не можете написати це так, оскільки компілятор буде скаржитися. Але, ей! Це проковтне цю жахливість:

public interface IMyContract : IEnumerable<int>, IEnumerable<long>
{
}

і навіть це:

public interface IMyContractAsync
{
    Task<int> Add(int a, int b);
}

public interface IMyContract : IMyContractAsync
{
    int Add(int a, int b);
}

Так це воно. Ви додаєте Async просто для того, щоб зупинити компілятор, щоб скаржитися. Не для уточнення речей. Щоб не зробити їх кращими. Якщо немає скарги - немає причини її додавати, тож у вашому випадку я цього уникну, якщо не стане Task<IAsyncEnumerable>.

PS: Просто для кращого розуміння всієї картини тут - якщо колись у майбутньому хтось додасть розширення квантово-комп’ютерного методу C # (фантазія, так), які будуть працювати в різній парадигмі, нам, мабуть, знадобиться інший суфікс на кшталт Quant або щось подібне, тому що C # поскаржиться інакше. Це буде точно такий же метод, але це зробить це по-іншому. Так само, як це робить поліморфізм. Як і інтерфейси.


1
Вибачте, але я не погоджуюся, що це не зовсім інший підхід робити те саме - це більше; очікується, що це буде називатися по-іншому, а результат буде зібраний по-різному. Це найбільша різниця між async та non-async. Я твердо вірю, що додавання асинхроніки є для наочності. Я думаю, що це також рекомендація Microsoft.
madoxdev

Так, я згоден, але не згоден. Як і в списку, у вас є проста функція сортування, а не "QuickSort", "RadixSort", "BubbleSort", "MixOfSorts". Вони різні, використовуються за сферою застосування, але, очевидно, не потрібні уточнення, крім випадків налагодження (я маю на увазі, що ви дбаєте про них лише тоді, коли вони впливають на продуктивність / ресурси). У цьому випадку DoThing та DoThingAsync знаходяться в тій же ситуації, що й будь-який інший шаблоновий алгоритм, їм не потрібно уточнення, він підтримується чи ні, і корисний лише для налагодження.
eocron

Це різні, асинхронні засоби - той, хто телефонує, переконайтеся, що ви попрацюєте з цим чітко. Факту відставки завдання недостатньо, щоб сказати, що метод справді Async. Абонент повинен знати, як чекати або використовувати GetAwaiter (). GetResilt (), щоб отримати той самий вихід. Це відрізняється не тим, як все робиться всередині.
madoxdev

Це цілком призначення аналізаторів коду та компілятора. IntellySense може легко вказати на це для вас, не потрібно використовувати мізки розробників для виділення або навіть вигнання з використанням методу синхронізації над асинхронним кодом в асинхронному коді. З мого досвіду під час використання Async мені рідко потрібно використовувати GetResult (), але мені часто потрібно забруднювати всю базу коду Async.
eocron

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