Saya menulis jenis implementasi Antrian yang memiliki TryDequeue
metode yang menggunakan pola yang mirip dengan berbagai TryParse
metode .NET , di mana saya mengembalikan nilai boolean jika tindakan berhasil, dan menggunakan out
parameter untuk mengembalikan nilai dequeued aktual.
public bool TryDequeue(out Message message) => _innerQueue.TryDequeue(out message);
Sekarang, saya suka menghindari out
params kapan pun saya bisa. C # 7 memberi kita delcarations variabel untuk membuatnya bekerja lebih mudah, tapi saya masih menganggap params lebih dari kejahatan yang diperlukan daripada alat yang berguna.
Perilaku yang saya inginkan dari metode ini adalah sebagai berikut:
- Jika ada item yang harus didekor, kembalikan.
- Jika tidak ada item yang harus di-dequeue (antrian kosong), berikan pemanggil informasi yang cukup untuk bertindak dengan tepat.
- Jangan hanya mengembalikan item nol jika tidak ada item yang tersisa.
- Jangan melemparkan pengecualian jika mencoba keluar dari antrian kosong.
Saat ini, pemanggil metode ini hampir selalu menggunakan pola seperti berikut (menggunakan sintaks variabel C # 7):
if (myMessageQueue.TryDequeue(out Message dequeued))
MyMessagingClass.SendMessage(dequeued)
else
Console.WriteLine("No messages!"); // do other stuff
Yang bukan yang terburuk, semua diceritakan. Tetapi saya merasa bahwa mungkin ada cara yang lebih baik untuk melakukan ini (saya benar-benar mau mengakui bahwa mungkin tidak ada). Aku benci bagaimana penelepon harus memecah alirannya dengan syarat ketika semua yang diinginkannya adalah mendapatkan nilai jika ada.
Apa beberapa pola lain yang ada untuk mencapai perilaku "coba" yang sama?
Untuk konteks, metode ini berpotensi disebut dalam proyek VB, jadi poin bonus untuk sesuatu yang berfungsi baik di keduanya. Namun, fakta ini seharusnya memiliki bobot yang sangat kecil.
Option<T>
struct dan kembalikan.bool Try(..., out data)
Fungsi - fungsi itu adalah kekejian.Jawaban:
Gunakan tipe Opsi, yang berarti objek tipe yang memiliki dua versi, biasanya disebut "Beberapa" (ketika ada nilai) atau "Tidak Ada" (ketika tidak ada nilai) ... Atau sesekali mereka disebut Adil dan Tidak Ada. Kemudian ada fungsi dalam tipe ini yang memungkinkan Anda mengakses nilai jika ada, menguji keberadaan, dan yang paling penting metode yang memungkinkan Anda menerapkan fungsi yang mengembalikan Opsi lebih lanjut ke nilai jika ada (biasanya dalam C # ini harus disebut FlatMap meskipun dalam bahasa lain sering disebut Bind, bukan ... Namanya sangat penting dalam C # karena memiliki metode nama dan tipe ini mari kita gunakan objek Opsi Anda dalam pernyataan LINQ).
Fitur tambahan dapat mencakup metode seperti IfPresent dan IfNotPresent untuk meminta tindakan dalam kondisi yang relevan, dan OrElse (yang menggantikan nilai default ketika tidak ada nilai tetapi tidak ada op sebaliknya), dan sebagainya.
Contoh Anda kemudian mungkin terlihat seperti:
Ini adalah pola Opsi (atau Mungkin) monad, dan ini sangat berguna. Ada implementasi yang ada (mis. Https://github.com/nlkl/Optional/blob/master/README.md ) tetapi tidak sulit untuk melakukannya juga.
(Anda mungkin ingin memperpanjang pola ini sehingga Anda mengembalikan deskripsi penyebab kesalahan alih-alih apa-apa ketika metode gagal ... Ini sepenuhnya dapat dicapai dan sering disebut monis Either; seperti namanya Anda dapat menggunakan FlatMap yang sama pola untuk membuatnya mudah untuk bekerja dengan dalam hal itu, juga)
sumber
Option
/Maybe
adalah bahwa itu adalah monad (jika diterapkan sebagai satu, tentu saja), yang berarti dapat dirantai dengan aman, dibungkus, dibuka, dan diproses tanpa perlu menangani kasus yang berbeda secara langsung, dan rantai ini dan pemrosesan dapat dilakukan dengan Ekspresi Kueri LINQ.flatMap
/bind
disebutSelectMany
di NET.Try...
konvensi penamaan di .NET (dan berpotensi membingungkan pengelola).Jawaban yang diberikan bagus dan saya akan pergi dengan salah satunya. Anggap jawaban ini hanya mengisi beberapa sudut dengan beberapa ide alternatif:
Buatlah subclass dari yang
Message
dipanggilSomeMessage
danNoMessage
.Dequeue
sekarang dapat kembaliNoMessage
jika tidak ada pesan, danSomeMessage
jika ada pesan. Jika callee peduli untuk mendeteksi di mana mereka berada, mereka dapat dengan mudah melakukannya dengan mengetik inspeksi. Jika mereka tidak, well,NoMessage
lakukan saja apa-apa setiap kali ada metode yang dipanggil, dan hei, mereka mendapatkan apa yang mereka minta.Sama seperti di atas, tetapi
Message
secara implisit dikonversi menjadibool
(atau mengimplementasikanoperator true / operator false
). Sekarang Anda dapat mengatakanif (message)
dan memilikinya benar jika pesannya baik dan salah jika itu buruk. (Ini hampir pasti ide yang buruk, tetapi saya memasukkannya untuk kelengkapan!)C # 7 memiliki tupel. Kembalikan
(bool, Message)
tuple.Buat
Message
tipe struct dan kembaliMessage?
.sumber
Di C # 7 Anda dapat menggunakan pencocokan pola untuk mencapai hal yang sama dengan cara yang lebih elegan:
Dalam kasus khusus ini, saya mungkin akan menggunakan acara daripada polling antrian berulang kali.
sumber
TryDequeue
mengembalikan beberapa antarmuka marker denganMessage
implementasi dan beberapa implementasi "tidak ada"? Tentu, ini lebih elegan di situs panggilan, tetapi Anda terjebak menerapkan 3 implementasi dalam kode aktual, yang itu sendiri mungkin tidak mungkin jikaMessage
merupakan tipe yang sudah ada.Tidak ada yang salah dengan metode Coba ... (memiliki parameter keluar) untuk skenario di mana kegagalan (tidak ada nilai) sama umum dengan keberhasilan.
Tetapi, jika Anda bersikeras melakukan sesuatu secara berbeda, Anda mungkin ingin mengembalikan pesan kosong dan hanya mengirimkannya (bukan masalah Anda lagi) atau menunda pernyataan if sampai Anda benar-benar harus tahu apakah Anda memiliki pesan dengan konten atau tidak.
Perhatikan bahwa bagaimanapun juga seseorang harus melakukan tes. Saya berpendapat tes harus dilakukan kapan dan di mana pertanyaannya saat ini. Ini pada saat dequeing.
sumber