Saya menonton pembicaraan Anders tentang C # 4.0 dan pratinjau diam-diam C # 5.0 , dan itu membuat saya berpikir tentang kapan parameter opsional tersedia di C # apa yang akan menjadi cara yang disarankan untuk menyatakan metode yang tidak memerlukan semua parameter yang ditentukan?
Misalnya sesuatu seperti FileStream
kelas memiliki sekitar lima belas konstruktor berbeda yang dapat dibagi menjadi 'keluarga' logis misalnya yang di bawah dari sebuah string, yang dari an IntPtr
dan yang dari a SafeFileHandle
.
FileStream(string,FileMode);
FileStream(string,FileMode,FileAccess);
FileStream(string,FileMode,FileAccess,FileShare);
FileStream(string,FileMode,FileAccess,FileShare,int);
FileStream(string,FileMode,FileAccess,FileShare,int,bool);
Tampak bagi saya bahwa jenis pola ini dapat disederhanakan dengan memiliki tiga konstruktor, dan menggunakan parameter opsional untuk salah satu yang dapat default, yang akan membuat keluarga konstruktor yang berbeda lebih berbeda [catatan: Saya tahu perubahan ini tidak akan terjadi dibuat di BCL, saya sedang berbicara hipotetis untuk jenis situasi ini].
Bagaimana menurut anda? Dari C # 4.0 akan lebih masuk akal untuk membuat kelompok konstruktor dan metode yang terkait erat sebagai metode tunggal dengan parameter opsional, atau adakah alasan yang baik untuk tetap menggunakan mekanisme banyak-kelebihan tradisional?
sumber
Ketika sebuah metode kelebihan beban biasanya melakukan hal yang sama dengan jumlah argumen yang berbeda, maka default akan digunakan.
Jika metode overload menjalankan fungsi secara berbeda berdasarkan parameternya, maka overloading akan terus digunakan.
Saya menggunakan opsional kembali di hari-hari VB6 saya dan sejak itu melewatkannya, itu akan mengurangi banyak duplikasi komentar XML di C #.
sumber
Saya telah menggunakan Delphi dengan parameter opsional selamanya. Saya telah beralih menggunakan kelebihan beban sebagai gantinya.
Karena ketika Anda membuat lebih banyak kelebihan, Anda akan selalu berkonflik dengan formulir parameter opsional, dan kemudian Anda harus mengubahnya menjadi non-opsional.
Dan saya suka anggapan bahwa umumnya ada satu metode super , dan sisanya adalah pembungkus sederhana di sekitarnya.
sumber
Foo(A, B, C)
membutuhkanFoo(A)
,Foo(B)
,Foo(C)
,Foo(A, B)
,Foo(A, C)
,Foo(B, C)
.Saya pasti akan menggunakan fitur parameter opsional 4.0. Itu menghilangkan konyol ...
... dan meletakkan nilainya tepat di tempat yang dapat dilihat penelepon ...
Jauh lebih sederhana dan jauh lebih sedikit rawan kesalahan. Saya sebenarnya telah melihat ini sebagai bug dalam kasus kelebihan beban ...
Saya belum bermain dengan compier 4.0, tetapi saya tidak akan terkejut mengetahui bahwa compier hanya mengeluarkan kelebihan beban untuk Anda.
sumber
Parameter opsional pada dasarnya adalah bagian dari metadata yang mengarahkan kompiler yang memproses panggilan metode untuk memasukkan default yang sesuai di situs panggilan. Sebaliknya, beban berlebih menyediakan sarana yang digunakan kompilator untuk memilih salah satu dari sejumlah metode, beberapa di antaranya mungkin menyediakan nilai default sendiri. Perhatikan bahwa jika seseorang mencoba memanggil metode yang menetapkan parameter opsional dari kode yang ditulis dalam bahasa yang tidak mendukungnya, compiler akan mengharuskan parameter "opsional" ditentukan, tetapi karena memanggil metode tanpa menentukan parameter opsional adalah setara dengan memanggilnya dengan parameter yang sama dengan nilai default, tidak ada kendala untuk bahasa seperti itu memanggil metode tersebut.
Konsekuensi signifikan dari pengikatan parameter opsional di situs panggilan adalah bahwa parameter tersebut akan diberi nilai berdasarkan versi kode target yang tersedia untuk kompilator. Jika sebuah assembly
Foo
memiliki metodeBoo(int)
dengan nilai default 5, dan assemblyBar
berisi panggilan keFoo.Boo()
, kompilator akan memprosesnya sebagai fileFoo.Boo(5)
. Jika nilai default diubah menjadi 6 dan perakitanFoo
dikompilasi ulang,Bar
akan terus memanggilFoo.Boo(5)
kecuali atau sampai itu dikompilasi ulang dengan versi baruFoo
. Oleh karena itu, seseorang harus menghindari penggunaan parameter opsional untuk hal-hal yang mungkin berubah.sumber
void Foo(int value) … void Foo() { Foo(42); }
. Dari luar, pemanggil tidak tahu nilai default apa yang digunakan, atau kapan nilai itu mungkin berubah; seseorang harus memantau dokumentasi tertulis untuk itu. Nilai default untuk parameter opsional dapat dilihat seperti itu: dokumentasi-dalam-kode apa nilai defaultnya.Dapat diperdebatkan apakah argumen opsional atau kelebihan beban harus digunakan atau tidak, tetapi yang terpenting, masing-masing memiliki area sendiri di mana mereka tidak tergantikan.
Argumen opsional, saat digunakan dalam kombinasi dengan argumen bernama, sangat berguna saat dikombinasikan dengan beberapa panggilan COM yang panjang-argumen-daftar-dengan-semua-opsional.
Overload sangat berguna ketika metode dapat beroperasi pada banyak tipe argumen yang berbeda (hanya satu dari contoh), dan melakukan pengecoran secara internal, misalnya; Anda cukup memberinya makan dengan tipe data apa pun yang masuk akal (yang diterima oleh beberapa kelebihan yang ada). Tidak bisa mengalahkan itu dengan argumen opsional.
sumber
Saya menantikan parameter opsional karena itu membuat default lebih dekat dengan metode. Jadi, alih-alih lusinan baris untuk kelebihan beban yang hanya memanggil metode "diperluas", Anda cukup menetapkan metode satu kali dan Anda dapat melihat parameter opsional apa yang digunakan secara default di tanda tangan metode. Saya lebih suka melihat:
Dari pada ini:
Jelas contoh ini sangat sederhana tetapi kasus di OP dengan 5 kelebihan beban, semuanya bisa menjadi sangat cepat.
sumber
Salah satu aspek favorit saya dari parameter opsional adalah Anda melihat apa yang terjadi pada parameter Anda jika Anda tidak menyediakannya, bahkan tanpa membuka definisi metode. Visual Studio hanya akan menunjukkan nilai default untuk parameter saat Anda mengetik nama metode. Dengan metode kelebihan beban, Anda tidak dapat membaca dokumentasi (bahkan jika tersedia) atau dengan langsung menavigasi ke definisi metode (jika tersedia) dan ke metode yang dibungkus oleh kelebihan beban.
Secara khusus: upaya dokumentasi dapat meningkat pesat dengan jumlah kelebihan muatan, dan Anda mungkin akan menyalin komentar yang sudah ada dari kelebihan muatan yang ada. Ini cukup mengganggu, karena tidak menghasilkan nilai apa pun dan melanggar prinsip KERING ). Di sisi lain, dengan parameter opsional, terdapat tepat satu tempat di mana semua parameter didokumentasikan dan Anda akan melihat artinya serta nilai defaultnya saat mengetik.
Last but not least, jika Anda adalah konsumen API, Anda bahkan mungkin tidak memiliki opsi untuk memeriksa detail implementasi (jika Anda tidak memiliki kode sumber) dan oleh karena itu tidak memiliki kesempatan untuk melihat metode super mana yang kelebihan beban sedang membungkus. Jadi Anda terjebak dengan membaca dokumen dan berharap bahwa semua nilai default terdaftar di sana, tetapi ini tidak selalu terjadi.
Tentu saja, ini bukan jawaban yang menangani semua aspek, tapi saya rasa ini menambahkan satu jawaban yang belum dibahas sejauh ini.
sumber
Meskipun keduanya (seharusnya?) Adalah dua cara yang setara secara konseptual yang tersedia bagi Anda untuk membuat model API dari awal, sayangnya keduanya memiliki beberapa perbedaan halus saat Anda perlu mempertimbangkan kompatibilitas runtime ke belakang untuk klien lama Anda di alam liar. Rekan saya (terima kasih Brent!) Mengarahkan saya ke posting yang luar biasa ini : Masalah versi dengan argumen opsional . Beberapa kutipan darinya:
sumber
Satu peringatan dari parameter opsional adalah pembuatan versi, di mana refactor memiliki konsekuensi yang tidak diinginkan. Sebuah contoh:
Kode awal
Asumsikan ini adalah salah satu dari banyak pemanggil metode di atas:
Di sini kejadiannya tidak diam dan diperlakukan sebagai kritis.
Sekarang katakanlah setelah refactor kita menemukan bahwa semua error meminta pengguna, jadi kita tidak lagi membutuhkan flag silent. Jadi kami menghapusnya.
Setelah refactor
Panggilan sebelumnya masih terkompilasi, dan katakanlah itu lolos dari refactor tidak berubah:
Sekarang
false
akan memiliki efek yang tidak diinginkan, acara tersebut tidak lagi dianggap kritis.Hal ini dapat mengakibatkan kerusakan yang tidak kentara, karena tidak akan ada kesalahan kompilasi atau runtime (tidak seperti beberapa peringatan opsional lainnya, seperti ini atau ini ).
Perhatikan bahwa ada banyak bentuk dari masalah yang sama ini. Satu bentuk lain diuraikan di sini .
Perhatikan juga bahwa secara ketat menggunakan parameter bernama saat memanggil metode akan menghindari masalah ini, seperti seperti ini:
HandleError("Disk is full", silent:false)
. Namun, mungkin tidak praktis untuk mengasumsikan bahwa semua pengembang lain (atau pengguna API publik) akan melakukannya.Untuk alasan ini saya akan menghindari penggunaan parameter opsional di API publik (atau bahkan metode publik jika mungkin digunakan secara luas) kecuali ada pertimbangan lain yang menarik.
sumber
Kedua parameter Opsional, Kelebihan metode memiliki kelebihan atau kekurangannya sendiri. Itu tergantung pada preferensi Anda untuk memilih di antara keduanya.
Parameter Opsional: hanya tersedia di .Net 4.0. parameter opsional mengurangi ukuran kode Anda. Anda tidak dapat menentukan parameter dan ref
metode kelebihan beban: Anda dapat Menentukan parameter Keluar dan ref. Ukuran kode akan meningkat tetapi metode yang kelebihan beban mudah dipahami.
sumber
Dalam banyak kasus, parameter opsional digunakan untuk mengalihkan eksekusi. Sebagai contoh:
Parameter diskon di sini digunakan untuk memberi makan pernyataan if-then-else. Ada polimorfisme yang tidak dikenali, dan kemudian diimplementasikan sebagai pernyataan if-then-else. Dalam kasus seperti itu, jauh lebih baik untuk membagi dua aliran kontrol menjadi dua metode independen:
Dengan cara ini, kami bahkan telah melindungi kelas dari menerima panggilan dengan diskon nol. Panggilan tersebut berarti bahwa penelepon berpikir bahwa ada diskon, tetapi sebenarnya tidak ada diskon sama sekali. Kesalahpahaman seperti itu dapat dengan mudah menyebabkan bug.
Dalam kasus seperti ini, saya memilih untuk tidak memiliki parameter opsional, tetapi untuk memaksa pemanggil secara eksplisit memilih skenario eksekusi yang sesuai dengan situasi saat ini.
Situasinya sangat mirip dengan memiliki parameter yang bisa nol. Itu ide yang sama buruknya ketika implementasi bermuara pada pernyataan seperti
if (x == null)
.Anda dapat menemukan analisis mendetail pada tautan ini: Menghindari Parameter Opsional dan Menghindari Parameter Nol
sumber
Untuk menambahkan no-brainer kapan harus menggunakan overload dan bukan opsional:
Kapanpun Anda memiliki sejumlah parameter yang hanya masuk akal jika digabungkan, jangan masukkan pilihan pada mereka.
Atau lebih umum lagi, setiap kali tanda tangan metode Anda mengaktifkan pola penggunaan yang tidak masuk akal, batasi jumlah permutasi panggilan yang mungkin. Misalnya, dengan menggunakan kelebihan beban, bukan opsional (aturan ini juga berlaku jika Anda memiliki beberapa parameter dari tipe data yang sama, omong-omong; di sini, perangkat seperti metode pabrik atau tipe data khusus dapat membantu).
Contoh:
sumber