Apakah ada konvensi penamaan yang pasti untuk metode pengembalian IAsyncEnumerable?

10

Setelah C # 5 memperkenalkan asyncdan awaitmemodelkan untuk pemrograman asinkron, komunitas C # tiba pada konvensi penamaan untuk menambahkan akhiran "Async" ke metode yang mengembalikan tipe yang ditunggu, seperti ini:

interface Foo
{
   Task BarAsync();
}

Banyak penganalisa kode statis (baik berbasis Roslyn dan non-Roslyn) sejak itu ditulis bergantung pada konvensi penamaan ini ketika mendeteksi bau kode di sekitar pemrograman asinkron.

Sekarang C # 8 telah memperkenalkan konsep enumerables asynchronous, yang sendiri tidak dapat ditunggu tetapi dapat digunakan bersamaan await foreach, tampaknya ada dua opsi untuk metode penamaan yang kembali IAsyncEnumerable:

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

atau

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

Apakah ada pedoman konvensi penamaan yang definitif (dari tim bahasa C #, .NET Foundation, atau pihak berwenang lainnya) mengenai opsi di atas, seperti bagaimana konvensi penamaan C # 5 distandarisasi dengan jelas dan tidak diserahkan kepada penilaian programmer berdasarkan pendapat?

hwaien
sumber
2
Opsi 2 terdengar benar di sini, karena Anda menjalankan kode ini secara tidak sinkron (tandai metode seperti asyncdan gunakan awaitdi dalam), dan sampel
msdn
1
Menanggapi penutupan pertanyaan, saya telah mengedit pertanyaan untuk menanyakan apakah ada konvensi penamaan definitif, dan untuk memberikan contoh bagaimana konvensi penamaan definitif dalam C # 5 menghasilkan perkembangan dalam analisis kode statis. Oleh karena itu memiliki C # 8 mengikuti pola itu akan menghasilkan peningkatan kualitas kode yang terukur di luar preferensi pengkodean berbasis pendapat.
hwaien
.NET Core sendiri menggunakan Asyncakhiran untuk metode yang kembali IAsyncEnumerable, misalnya ChannelReader.ReadAllAsync . Dalam kasus lain, misalnya dalam EF Core, AsAsyncEnumerable()digunakan yang sudah jelas
Panagiotis Kanavos
Pedoman penamaan ada untuk memudahkan manusia memahami kode. Jika tujuan kode tidak jelas, tambahkan akhiran.
Panagiotis Kanavos

Jawaban:

1

Tidak ada pedoman yang lebih baik daripada apa yang sudah dilakukan oleh tim .NET :

  • ChannelReader.ReadAllAsync mengembalikan sebuahIAsyncEnumerable<T>
  • Di EF Core 3, hasilnya dikembalikan sebagai IAsyncEnumerabledengan memanggil AsAsyncEnumerable ()
  • Dalam System.Linq.Async, ToAsyncEnumerable () mengkonversi IEnumerables, Tugas dan diamati dalam IAsyncEnumerables
  • Semua operator lain System.Linq.Asyncmempertahankan nama mereka. Tidak ada SelectAsyncatau SelectAsAsyncEnumerable, adil Select.

Dalam semua kasus, jelas apa hasil dari metode ini. Dalam semua kasus, hasil dari metode harus ditunggu await foreachsebelum mereka dapat digunakan.

Jadi pedoman sebenarnya tetap sama - pastikan namanya membuat perilaku jelas :

  • Ketika nama sudah jelas, misalnya dengan AsAsyncEnumerable()atau ToAsyncEnumerable(), tidak perlu menambahkan akhiran apa pun.
  • Dalam kasus lain, tambahkan Asyncakhiran agar pengembang tahu mereka perlu await foreachhasilnya.

Penganalisa kode dan generator tidak terlalu peduli dengan nama metode, mereka mendeteksi bau dengan memeriksa kode itu sendiri. Sebuah analisa kode akan memberitahu Anda bahwa Anda lupa untuk menunggu Tugas atau await foreachsebuah IAsyncEnumerabletidak peduli bagaimana Anda memanggil metode dan variabel. Generator cukup menggunakan refleksi untuk memeriksa IAsyncEnumerabledan memancarkanawait foreach

Ini adalah gaya analisis yang memeriksa nama-nama. Tugas mereka adalah memastikan kode menggunakan gaya yang konsisten sehingga pengembang dapat memahami kode tersebut. Penganalisis gaya akan memberi tahu Anda bahwa suatu metode tidak mengikuti gaya yang Anda pilih. Gaya itu bisa menjadi panduan gaya tim atau yang umum diterima.

Dan tentu saja, semua orang tahu awalan umum untuk bidang instance pribadi adalah _:)

Panagiotis Kanavos
sumber
Terima kasih telah menunjukkan ChannelReader.ReadAllAsynccontohnya. Karena ini datang langsung dari tim .NET, sulit untuk salah mengikuti.
hwaien
Paket Analyzer sering disertai dengan tas analisis gaya dan non-gaya. Misalnya, paket Microsoft.VisualStudio.Threading.Analyzers memiliki penganalisis gaya yang memeriksa konvensi penamaan (VSTHRD200) dan penganalisis non-gaya yang mendeteksi situasi berbahaya yang berpotensi menyebabkan kebuntuan (VSTHRD111). Untuk referensi paket untuk memanfaatkan VSTHRD111, sebuah proyek juga akan berakhir dengan VSTHRD200.
hwaien
2

Ini bukan metode async, jadi nama tidak boleh diakhiri dengan 'Async'. Suffix metode itu adalah konvensi untuk memperjelas bahwa metode itu harus ditunggu, atau hasilnya ditangani sebagai Tugas.

Saya pikir nama yang mengembalikan koleksi normal adalah tepat. GetFoos (), atau serupa.

David Browne - Microsoft
sumber
Semua itu adalah argumen untuk menggunakan Asyncsuffix. Sufiks digunakan dalam .NET Core sendiri: ChannelReader.ReadAllAsync mengembalikan IAsyncEnumerable. Sebuah IAsyncEnumerableharus digunakan dengan await foreach, sehingga akhiran masuk akal.
Panagiotis Kanavos
1

Async suffix dan bahkan kata kunci asynchanya boilerplate, tidak ada artinya selain beberapa argumen keterbelakangan. C # memiliki semua informasi untuk membedakan fungsi-fungsi itu sama seperti perbedaan yielddalam metode yang kembali IEnumerable, karena Anda tahu Anda tidak perlu menambahkan sesuatu seperti enumerableatau beberapa kata kunci lain pada metode tersebut.

Anda perlu menambahkan akhiran Async hanya karena C # akan mengeluh tentang kelebihan, jadi pada dasarnya keduanya sama dan mereka melakukan hal yang sama dengan semua aturan polimorfisme (jika kita tidak memperhitungkan faktor manusia dari perilaku yang merusak secara intenasional):

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

Tetapi Anda tidak dapat menulisnya seperti ini karena kompilator akan mengeluh. Tapi hey! Ini akan menelan monstrositas yang satu ini:

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

dan bahkan ini:

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

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

Jadi ini dia. Anda menambahkan Async hanya untuk menghentikan kompiler untuk mengeluh. Bukan untuk mengklarifikasi hal-hal. Bukan untuk membuat mereka lebih baik. Jika tidak ada keluhan - tidak ada alasan untuk menambahkannya, maka dalam kasus Anda, saya akan menghindari ini, kecuali jika itu terjadi Task<IAsyncEnumerable>.

PS: Hanya untuk lebih memahami seluruh gambar di sini - jika suatu saat nanti seseorang menambahkan ekstensi metode komputer C # (fantazy, huh) yang akan beroperasi dalam paradigma yang berbeda, kita mungkin akan membutuhkan akhiran lain seperti Quant atau sesuatu, karena C # akan mengeluh sebaliknya. Ini akan menjadi metode yang sama persis tetapi itu akan bekerja dengan cara lain. Seperti halnya polimorfisme. Sama seperti antarmuka lakukan.

eocron
sumber
1
Maaf, tetapi saya merasa saya tidak setuju, ini bukan pendekatan yang benar-benar berbeda dalam melakukan hal yang sama - itu; lebih - itu diharapkan disebut berbeda, dan hasilnya dikumpulkan secara berbeda. Itulah perbedaan paling besar antara async dan non-async. Saya sangat percaya menambahkan async adalah untuk kejelasan. Saya pikir ini juga rekomendasi Microsoft.
madoxdev
Ya, saya setuju tetapi tidak setuju. Sama seperti dalam Daftar Anda memiliki fungsi Urutkan sederhana dan bukan "QuickSort", "RadixSort", "BubbleSort", "MixOfSorts". Mereka berbeda, digunakan oleh lingkup tetapi jelas tidak membutuhkan klarifikasi selain untuk tujuan debugging (maksud saya Anda hanya peduli pada mereka ketika mereka berdampak pada kinerja / sumber daya). Dalam hal ini DoThing dan DoThingAsync berada dalam situasi yang sama daripada algoritma templated lainnya, mereka tidak memerlukan klarifikasi, apakah didukung atau tidak, dan hanya bermanfaat untuk debugging.
eocron
Itu berbeda, berarti async - heu penelepon pastikan Anda menangani ini dengan benar. Fakta pensiunan Tugas tidak cukup untuk mengatakan bahwa metode ini benar-benar Async. Pemanggil harus tahu untuk menunggu atau menggunakan GetAwaiter (). GetResilt () untuk mendapatkan oitput yang sama. Itu berbeda bukan bagaimana hal-hal dilakukan di dalam.
madoxdev
Ini sepenuhnya tujuan penganalisa kode dan kompilator. IntellySense dapat dengan mudah menunjukkan ini untuk Anda, tidak perlu menggunakan otak pengembang untuk menyorot atau bahkan membuang penggunaan metode sinkronisasi di atas async satu dalam kode asinkron. Dari pengalaman saya ketika menggunakan Async saya jarang perlu menggunakan GetResult (), tapi saya sering perlu mencemari seluruh basis kode dengan Async.
eocron
Sebagai seseorang menandai itu - itu adalah opini. Kita bisa tetap percaya pada apa yang kita yakini dan menjadi bahagia :)
madoxdev