Saya ingin menulis metode async dengan out
parameter, seperti ini:
public async void Method1()
{
int op;
int result = await GetDataTaskAsync(out op);
}
Bagaimana saya melakukan ini GetDataTaskAsync
?
sumber
Saya ingin menulis metode async dengan out
parameter, seperti ini:
public async void Method1()
{
int op;
int result = await GetDataTaskAsync(out op);
}
Bagaimana saya melakukan ini GetDataTaskAsync
?
Anda tidak dapat memiliki metode ref
atau out
parameter async .
Lucian Wischik menjelaskan mengapa ini tidak mungkin pada utas MSDN ini: http://social.msdn.microsoft.com/Forums/en-US/d2f48a52-e35a-4948-844d-828a1a6deb74/why-async-methods-cannot-have -ref-atau-out-parameter
Adapun mengapa metode async tidak mendukung parameter out-by-reference? (atau parameter ref?) Itu batasan dari CLR. Kami memilih untuk mengimplementasikan metode async dengan cara yang mirip dengan metode iterator - yaitu melalui kompiler yang mentransformasikan metode tersebut menjadi objek-mesin-objek. CLR tidak memiliki cara aman untuk menyimpan alamat "parameter keluar" atau "parameter referensi" sebagai bidang objek. Satu-satunya cara untuk mendukung parameter referensi-keluar adalah jika fitur async dilakukan oleh penulisan ulang CLR tingkat rendah alih-alih penulisan ulang kompiler. Kami memeriksa pendekatan itu, dan banyak yang harus dilakukan untuk itu, tetapi pada akhirnya akan sangat mahal sehingga tidak akan pernah terjadi.
Solusi khas untuk situasi ini adalah memiliki metode async mengembalikan Tuple sebagai gantinya. Anda dapat menulis ulang metode Anda seperti itu:
public async Task Method1()
{
var tuple = await GetDataTaskAsync();
int op = tuple.Item1;
int result = tuple.Item2;
}
public async Task<Tuple<int, int>> GetDataTaskAsync()
{
//...
return new Tuple<int, int>(1, 2);
}
Tuple
alternatifnya. Sangat membantu.Tuple
. : PAnda tidak dapat memiliki
ref
atauout
parameter dalamasync
metode (seperti yang telah dicatat).Ini menjerit untuk beberapa pemodelan dalam data yang bergerak di sekitar:
Anda mendapatkan kemampuan untuk menggunakan kembali kode Anda dengan lebih mudah, plus cara itu lebih mudah dibaca daripada variabel atau tupel.
sumber
Solusi C # 7 + adalah menggunakan sintaks tuple implisit.
hasil kembali menggunakan metode tanda tangan nama properti yang ditentukan. misalnya:
sumber
Alex membuat poin bagus pada keterbacaan. Sama dengan itu, suatu fungsi juga antarmuka yang cukup untuk menentukan jenis yang dikembalikan dan Anda juga mendapatkan nama variabel yang bermakna.
Penelepon menyediakan lambda (atau fungsi bernama) dan intellisense membantu dengan menyalin nama variabel dari delegasi.
Pendekatan khusus ini seperti metode "Coba" di mana
myOp
diatur jika hasil metodetrue
. Kalau tidak, Anda tidak pedulimyOp
.sumber
Salah satu fitur
out
parameter yang bagus adalah mereka dapat digunakan untuk mengembalikan data bahkan ketika suatu fungsi melempar pengecualian. Saya pikir setara terdekat untuk melakukan ini denganasync
metode akan menggunakan objek baru untuk menyimpan data yangasync
dapat merujuk pada metode dan pemanggil. Cara lain adalah dengan meloloskan seorang delegasi seperti yang disarankan dalam jawaban lain .Perhatikan bahwa tidak satu pun dari teknik ini akan memiliki semacam penegakan dari kompiler yang
out
dimiliki. Yaitu, kompiler tidak akan mengharuskan Anda untuk menetapkan nilai pada objek bersama atau memanggil delegasi yang lewat.Berikut adalah contoh implementasi menggunakan objek bersama untuk meniru
ref
danout
untuk digunakan denganasync
metode dan berbagai skenario lainnya di manaref
danout
tidak tersedia:sumber
Saya suka
Try
polanya. Ini pola yang rapi.Tapi, itu menantang
async
. Itu tidak berarti kita tidak memiliki opsi nyata. Berikut adalah tiga pendekatan inti yang dapat Anda pertimbangkan untukasync
metode dalam versi kuasi dariTry
pola.Pendekatan 1 - menampilkan struktur
Ini terlihat paling seperti
Try
metode sinkronisasi hanya mengembalikantuple
bukan denganbool
denganout
parameter, yang kita semua tahu tidak diizinkan dalam C #.Dengan metode yang kembali
true
darifalse
dan tidak pernah melemparexception
.Pendekatan 2 - metode panggilan balik masuk
Kita dapat menggunakan
anonymous
metode untuk mengatur variabel eksternal. Sintaksnya pintar, meski sedikit rumit. Dalam dosis kecil, tidak apa-apa.Metode ini mematuhi dasar-dasar
Try
pola tetapi menetapkanout
parameter untuk diteruskan dalam metode panggilan balik. Ini dilakukan seperti ini.Pendekatan 3 - gunakan ContinueWith
Bagaimana jika Anda hanya menggunakan yang
TPL
dirancang? Tidak ada tupel. Idenya di sini adalah bahwa kami menggunakan pengecualian untuk mengarahkan ulangContinueWith
ke dua jalur yang berbeda.Dengan metode yang melempar
exception
ketika ada segala jenis kegagalan. Itu berbeda dari mengembalikan aboolean
. Ini cara untuk berkomunikasi denganTPL
.Dalam kode di atas, jika file tidak ditemukan, pengecualian dilemparkan. Ini akan memanggil kegagalan
ContinueWith
yang akan menanganiTask.Exception
blok logikanya. Rapi, ya?Semoga berhasil.
sumber
ContinueWith
panggilan chaining memiliki hasil yang diharapkan? Menurut pemahaman saya yang keduaContinueWith
akan memeriksa keberhasilan kelanjutan pertama, bukan keberhasilan tugas aslinya.Saya memiliki masalah yang sama seperti saya suka menggunakan Try-method-pattern yang pada dasarnya tampaknya tidak sesuai dengan async-await-paradigm ...
Yang penting bagi saya adalah bahwa saya dapat memanggil Try-method dalam satu if-klausa dan tidak harus menentukan variabel-out sebelumnya, tetapi dapat melakukannya secara in-line seperti pada contoh berikut:
Jadi saya datang dengan solusi berikut:
Tentukan struct pembantu:
Tetapkan async Try-method seperti ini:
Panggil metode Try async seperti ini:
Untuk beberapa parameter keluar, Anda dapat menentukan struct tambahan (mis. AsyncOut <T, OUT1, OUT2>) atau Anda dapat mengembalikan tuple.
sumber
Batasan
async
metode yang tidak menerimaout
parameter hanya berlaku untuk metode async yang dihasilkan oleh kompiler, ini dinyatakan denganasync
kata kunci. Itu tidak berlaku untuk metode async kerajinan tangan. Dengan kata lain dimungkinkan untuk membuatTask
metode pengembalian menerimaout
parameter. Misalnya katakanlah kita sudah memilikiParseIntAsync
metode yang melempar, dan kami ingin membuatTryParseIntAsync
yang tidak melempar. Kita bisa menerapkannya seperti ini:Menggunakan
TaskCompletionSource
danContinueWith
metode ini agak canggung, tetapi tidak ada pilihan lain karena kita tidak dapat menggunakanawait
kata kunci yang mudah digunakan di dalam metode ini.Contoh penggunaan:
Pembaruan: Jika logika async terlalu kompleks untuk diekspresikan tanpa
await
, maka itu bisa dienkapsulasi di dalam delegasi anonim sinkron asinkron. ATaskCompletionSource
masih diperlukan untukout
parameter. Ada kemungkinan bahwaout
parameter dapat diselesaikan sebelum penyelesaian tugas utama, seperti dalam contoh di bawah ini:Contoh ini mengasumsikan adanya tiga metode asinkron
GetResponseAsync
,GetRawDataAsync
danFilterDataAsync
itu disebut berturut-turut. Theout
parameter selesai pada penyelesaian metode kedua. TheGetDataAsync
Metode dapat digunakan seperti ini:Menunggu
data
sebelum menunggurawDataLength
adalah penting dalam contoh sederhana ini, karena dalam kasus pengecualianout
parameter tidak akan pernah selesai.sumber
Saya pikir menggunakan ValueTuples seperti ini bisa berhasil. Anda harus menambahkan paket ValueTuple NuGet terlebih dahulu:
sumber
Berikut kode jawaban @ dcastro yang dimodifikasi untuk C # 7.0 dengan nama tuple dan tuple deconstruction, yang merampingkan notasi:
Untuk detail tentang tupel bernama baru, tuple literal dan dekonstruksi tuple lihat: https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/
sumber
Anda dapat melakukan ini dengan menggunakan TPL (task parallel library) alih-alih langsung menggunakan kata kunci tunggu.
sumber