Apa cara paling elegan untuk memanggil metode async dari pengambil atau penyetel di C #?
Berikut ini beberapa pseudo-code untuk membantu menjelaskan diri saya.
async Task<IEnumerable> MyAsyncMethod()
{
return await DoSomethingAsync();
}
public IEnumerable MyList
{
get
{
//call MyAsyncMethod() here
}
}
Task<T>
, yang akan segera kembali, memiliki semantik properti normal, dan masih memungkinkan hal-hal diperlakukan secara asinkron sesuai kebutuhan.Jawaban:
Tidak ada alasan teknis bahwa
async
properti tidak diizinkan dalam C #. Itu adalah keputusan desain yang disengaja, karena "sifat asinkron" adalah sebuah oxymoron.Properti harus mengembalikan nilai saat ini; mereka seharusnya tidak memulai operasi latar belakang.
Biasanya, ketika seseorang menginginkan "properti asinkron", yang sebenarnya mereka inginkan adalah salah satunya:
async
metode.async
metode pabrik untuk objek yang berisi atau gunakanasync InitAsync()
metode. Nilai yang terikat data akandefault(T)
sampai nilai dihitung / diambil.AsyncLazy
dari blog saya atau perpustakaan AsyncEx . Ini akan memberi Andaawait
properti yang bisa.Pembaruan: Saya membahas properti asinkron di salah satu posting blog "async OOP" terbaru saya.
sumber
Dispatcher.CurrentDispatcher.Invoke(new Action(..)
?INotifyPropertyChanged
, lalu putuskan apakah Anda ingin nilai lama dikembalikan ataudefault(T)
saat pembaruan asinkron sedang dalam penerbangan.NotifyTaskCompletion
dari proyek AsyncEx saya . Atau Anda bisa membangun sendiri; tidak sesulit itu.{Binding PropName.Result}
tidak sepele bagi saya untuk mencari tahu.Anda tidak dapat menyebutnya asinkron, karena tidak ada dukungan properti asinkron, hanya metode asinkron. Dengan demikian, ada dua opsi, keduanya mengambil keuntungan dari fakta bahwa metode asinkron dalam CTP benar-benar hanya metode yang mengembalikan
Task<T>
atauTask
:Atau:
sumber
private async void SetupList() { MyList = await MyAsyncMethod(); }
ini akan menyebabkan MyList diatur (dan kemudian secara otomatis mengikat, jika mengimplementasikan INPC) segera setelah operasi async selesai ...getTitle()
bersamaan ...Saya benar-benar membutuhkan panggilan untuk berasal dari metode get, karena arsitektur dipisahkan saya. Jadi saya datang dengan implementasi berikut.
Penggunaan: Judul dalam ViewModel atau objek yang bisa Anda deklarasikan secara statis sebagai sumber halaman. Ikat padanya dan nilainya akan dipopulasi tanpa memblokir UI, ketika getTitle () kembali.
sumber
Saya pikir kita bisa menunggu nilainya hanya mengembalikan nol pertama dan kemudian mendapatkan nilai nyata, jadi dalam kasus Pure MVVM (proyek PCL misalnya) saya pikir yang berikut ini adalah solusi paling elegan:
sumber
CS4014: Async method invocation without an await expression
async void
hanya untuk penangan tingkat atas dan sejenisnya". Saya pikir ini mungkin memenuhi syarat sebagai "dan sejenisnya".Anda bisa menggunakan
Task
seperti ini:sumber
Saya pikir .GetAwaiter (). GetResult () adalah solusi tepat untuk masalah ini, bukan? misalnya:
sumber
.Result
- itu bukan asinkron dan dapat mengakibatkan kebuntuan.Karena "properti async" Anda ada dalam model tampilan, Anda bisa menggunakan AsyncMVVM :
Ini akan menangani konteks sinkronisasi dan pemberitahuan perubahan properti untuk Anda.
sumber
Necromancing.
Di .NET Core / NetStandard2, Anda bisa menggunakan
Nito.AsyncEx.AsyncContext.Run
alih-alihSystem.Windows.Threading.Dispatcher.InvokeAsync
:Jika Anda hanya memilih
System.Threading.Tasks.Task.Run
atauSystem.Threading.Tasks.Task<int>.Run
, maka itu tidak akan berhasil.sumber
Saya pikir contoh saya di bawah ini mungkin mengikuti pendekatan @ Stephen-Cleary tetapi saya ingin memberikan contoh kode. Ini untuk digunakan dalam konteks pengikatan data misalnya Xamarin.
Konstruktor kelas - atau memang setter properti lain di mana ia bergantung - dapat menyebut kekosongan async yang akan mengisi properti pada penyelesaian tugas tanpa perlu menunggu atau memblokir. Ketika akhirnya mendapatkan nilai, itu akan memperbarui UI Anda melalui mekanisme NotifyPropertyChanged.
Saya tidak yakin tentang efek samping dari memanggil aysnc batal dari konstruktor. Mungkin komentator akan menguraikan penanganan kesalahan dll.
sumber
Ketika saya mengalami masalah ini, mencoba menjalankan sinkronisasi metode async baik dari setter atau konstruktor membuat saya menemui jalan buntu pada utas UI, dan menggunakan event handler memerlukan terlalu banyak perubahan dalam desain umum.
Solusinya adalah, seperti sering, hanya menulis secara eksplisit apa yang saya inginkan terjadi secara implisit, yaitu memiliki utas lain menangani operasi dan mendapatkan utas utama untuk menunggu sampai selesai:
Anda bisa membantah bahwa saya menyalahgunakan kerangka kerja, tetapi itu berhasil.
sumber
Saya meninjau semua jawaban tetapi semua memiliki masalah kinerja.
misalnya di:
Deployment.Current.Dispatcher.InvokeAsync (async () => {Judul = menunggu getTitle ();});
gunakan operator yang bukan jawaban yang baik.
tetapi ada solusi sederhana, lakukan saja:
sumber
Anda dapat mengubah proerty menjadi
Task<IEnumerable>
dan lakukan sesuatu seperti:
dan gunakan seperti menunggu MyList;
sumber