Saya telah berpikir tentang membuat jenis khusus untuk pengidentifikasi seperti ini:
public enum CustomerId : int { /* intentionally empty */ }
public enum OrderId : int { }
public enum ProductId : int { }
Motivasi utama saya untuk ini adalah untuk mencegah jenis bug di mana Anda secara tidak sengaja mengirimkan orderItemId ke fungsi yang mengharapkan orderItemDetailId.
Tampaknya enum bekerja mulus dengan semua yang ingin saya gunakan dalam aplikasi web .NET yang khas:
- Routing MVC bekerja dengan baik
- Serialisasi JSON berfungsi dengan baik
- Setiap ORM saya bisa memikirkan berfungsi dengan baik
Jadi sekarang saya bertanya-tanya, "mengapa saya tidak melakukan ini?" Ini adalah satu-satunya kekurangan yang dapat saya pikirkan:
- Ini dapat membingungkan pengembang lain
- Ini memperkenalkan inkonsistensi dalam sistem Anda jika Anda memiliki pengidentifikasi non-integral.
- Mungkin memerlukan casting tambahan, seperti
(CustomerId)42
. Tapi saya tidak berpikir ini akan menjadi masalah, karena routing ORM dan MVC biasanya akan memberikan Anda nilai-nilai dari tipe enum secara langsung.
Jadi pertanyaan saya adalah, apa yang saya lewatkan? Ini mungkin ide yang buruk, tetapi mengapa?
Jawaban:
Merupakan ide bagus untuk membuat tipe untuk setiap jenis pengidentifikasi, terutama untuk alasan yang Anda nyatakan. Saya tidak akan melakukannya dengan mengimplementasikan tipe enum karena menjadikannya struct atau kelas yang tepat memberi Anda lebih banyak opsi:
Anda dapat membaca tentang penerapannya di artikel Fungsional C #: Obsesi primitif .
sumber
Ini adalah hack yang cerdik, tetapi masih merupakan hack yang menyalahgunakan fitur untuk sesuatu yang bukan tujuan yang dimaksudkan. Hacks memiliki biaya dalam pemeliharaan, jadi itu tidak cukup Anda tidak dapat menemukan kekurangan lain, itu juga perlu memiliki manfaat yang signifikan dibandingkan dengan cara yang lebih idiomatis untuk menyelesaikan masalah yang sama.
Cara idiomatis adalah dengan membuat tipe pembungkus atau struct dengan satu bidang. Ini akan memberi Anda keamanan jenis yang sama dengan cara yang lebih eksplisit dan idiomatik. Meskipun proposal Anda memang pandai, saya tidak melihat keuntungan signifikan apa pun dalam menggunakan jenis pembungkus.
sumber
Dari POV saya, idenya bagus. Niat untuk memberikan tipe yang berbeda untuk kelas pengidentifikasi yang tidak terkait, dan mengekspresikan semantik melalui tipe dan membiarkan kompiler memeriksanya, adalah yang baik.
Saya tidak tahu cara kerjanya di. NET kinerja-bijaksana, misalnya adalah nilai-nilai enum tentu kotak. Kode OTOH yang bekerja dengan basis data kemungkinan I / O-terikat pula dan pengidentifikasi kotak tidak akan menjadi hambatan.
Di dunia yang sempurna, pengidentifikasi tidak akan berubah dan hanya dapat dibandingkan untuk kesetaraan; byte aktual akan menjadi detail implementasi. Pengidentifikasi yang tidak terkait akan memiliki tipe yang tidak kompatibel sehingga Anda tidak dapat menggunakan satu untuk yang lain secara tidak sengaja. Solusi Anda praktis sesuai dengan tagihan.
sumber
Anda tidak dapat melakukan ini, enum harus ditentukan sebelumnya. Jadi, kecuali jika Anda bersedia menentukan sebelumnya seluruh spektrum nilai yang mungkin dari id pelanggan, jenis Anda tidak akan berguna.
Jika Anda memilih, Anda akan menentang tujuan utama Anda untuk mencegah untuk secara tidak sengaja menetapkan id tipe A ke id tipe B. Jadi enum tidak membantu tujuan Anda.
Ini memunculkan pertanyaan, apakah akan membantu untuk membuat tipe Anda untuk id pelanggan, id pesanan dan id produk dengan turun dari Int32 (atau Guid). Saya bisa memikirkan alasan mengapa ini salah.
Tujuan dari id adalah identifikasi. Tipe integral sudah sempurna untuk ini, mereka tidak mendapatkan identitas lagi dengan turun darinya. Tidak ada spesialisasi yang diperlukan atau diinginkan, dunia Anda tidak akan terwakili dengan lebih baik dengan memiliki jenis pengenal yang berbeda. Jadi dari perspektif OO itu akan buruk.
Dengan saran Anda, Anda menginginkan lebih dari keamanan jenis, Anda menginginkan keamanan nilai dan yang berada di luar domain pemodelan, itu adalah masalah operasional.
sumber
public ActionResult GetCustomer(CustomerId custId)
casting tidak diperlukan - kerangka kerja MVC akan memberikan nilai.