Tampaknya sintaks penginisialisasi objek C # 3.0 memungkinkan seseorang untuk mengecualikan pasangan buka / tutup tanda kurung di konstruktor ketika ada konstruktor tanpa parameter. Contoh:
var x = new XTypeName { PropA = value, PropB = value };
Sebagai lawan:
var x = new XTypeName() { PropA = value, PropB = value };
Saya ingin tahu mengapa pasangan kurung buka / tutup konstruktor opsional di sini setelahnya XTypeName
?
c#
syntax
types
language-design
initializer
James Dunne
sumber
sumber
Jawaban:
Pertanyaan ini menjadi subjek blog saya pada tanggal 20 September 2010 . Jawaban Josh dan Chad ("mereka tidak menambah nilai jadi mengapa membutuhkannya?" Dan "untuk menghilangkan redundansi") pada dasarnya benar. Untuk menyempurnakannya sedikit lagi:
Fitur yang memungkinkan Anda untuk memilih daftar argumen sebagai bagian dari "fitur yang lebih besar" dari penginisialisasi objek memenuhi bilah kami untuk fitur "manis". Beberapa poin yang kami pertimbangkan:
Perhatikan kembali daftar kriteria di atas. Salah satunya adalah bahwa perubahan tersebut tidak menimbulkan ambiguitas baru dalam analisis leksikal, gramatikal atau semantik suatu program. Perubahan yang Anda usulkan memang memperkenalkan ambiguitas analisis semantik:
Baris 1 membuat C baru, memanggil konstruktor default, lalu memanggil metode instance M pada objek baru. Baris 2 membuat instance baru BM dan memanggil konstruktor defaultnya. Jika tanda kurung pada baris 1 bersifat opsional maka baris 2 akan menjadi ambigu. Kami kemudian harus membuat aturan untuk menyelesaikan ambiguitas; kami tidak dapat membuatnya menjadi kesalahan karena itu akan menjadi perubahan yang merusak yang mengubah program C # legal yang ada menjadi program rusak.
Oleh karena itu, aturannya harus sangat rumit: pada dasarnya tanda kurung hanya opsional jika tidak menimbulkan ambiguitas. Kami harus menganalisis semua kemungkinan kasus yang menyebabkan ambiguitas dan kemudian menulis kode di compiler untuk mendeteksinya.
Dalam terang itu, kembali dan lihat semua biaya yang saya sebutkan. Berapa banyak dari mereka sekarang menjadi besar? Aturan yang rumit memiliki biaya desain, spesifikasi, pengembangan, pengujian, dan dokumentasi yang besar. Aturan yang rumit lebih cenderung menyebabkan masalah dengan interaksi tak terduga dengan fitur di masa mendatang.
Semuanya untuk apa? Manfaat pelanggan kecil yang tidak menambahkan kekuatan representasi baru ke bahasa, tetapi menambahkan kasus sudut gila hanya menunggu untuk meneriakkan "gotcha" pada beberapa jiwa malang yang tidak curiga yang menabraknya. Fitur seperti itu segera dipotong dan dimasukkan ke dalam daftar "jangan pernah lakukan ini".
Yang itu segera menjadi jelas; Saya cukup akrab dengan aturan di C # untuk menentukan kapan nama putus-putus diharapkan.
Ketiganya. Sebagian besar kita hanya melihat spesifikasi dan mie di atasnya, seperti yang saya lakukan di atas. Misalnya, kita ingin menambahkan operator awalan baru ke C # yang disebut "frob":
(UPDATE:
frob
tentu sajaawait
; analisis di sini pada dasarnya adalah analisis yang dilakukan tim desain saat menambahkanawait
.)"frob" di sini seperti "baru" atau "++" - ia muncul sebelum semacam ekspresi. Kami akan mengerjakan prioritas dan asosiatif yang diinginkan dan seterusnya, dan kemudian mulai mengajukan pertanyaan seperti "bagaimana jika program sudah memiliki jenis, bidang, properti, peristiwa, metode, konstanta, atau lokal yang disebut frob?" Itu akan segera mengarah pada kasus seperti:
apakah itu berarti "lakukan operasi frob pada hasil x = 10, atau buat variabel berjenis frob yang disebut x dan tetapkan 10 untuk itu?" (Atau, jika frobbing menghasilkan variabel, itu bisa menjadi penugasan 10 ke
frob x
. Lagi pula,*x = 10;
parsing dan legal jikax
adaint*
.)Apakah itu berarti "frob hasil dari operator plus unary pada x" atau "tambahkan ekspresi frob ke x"?
Dan seterusnya. Untuk mengatasi ambiguitas ini, kami mungkin memperkenalkan heuristik. Saat Anda mengucapkan "var x = 10;" itu ambigu; ini bisa berarti "menyimpulkan tipe dari x" atau bisa juga berarti "x adalah tipe var". Jadi kita memiliki heuristik: pertama kita mencoba mencari tipe bernama var, dan hanya jika tidak ada kita menyimpulkan tipe x.
Atau, kami mungkin mengubah sintaks agar tidak ambigu. Ketika mereka merancang C # 2.0, mereka mengalami masalah ini:
Apakah itu berarti "hasil x dalam sebuah iterator" atau "panggil metode hasil dengan argumen x?" Dengan mengubahnya menjadi
sekarang tidak ambigu.
Dalam kasus parens opsional dalam penginisialisasi objek, sangat mudah untuk mempertimbangkan apakah ada ambiguitas yang diperkenalkan atau tidak karena jumlah situasi di mana diperbolehkan untuk memperkenalkan sesuatu yang dimulai dengan {sangat kecil . Pada dasarnya hanya berbagai konteks pernyataan, pernyataan lambdas, penginisialisasi array dan hanya itu. Sangat mudah untuk bernalar melalui semua kasus dan menunjukkan bahwa tidak ada ambiguitas. Memastikan IDE tetap efisien agak lebih sulit tetapi dapat dilakukan tanpa terlalu banyak masalah.
Mengotak-atik spesifikasi seperti ini biasanya sudah cukup. Jika itu adalah fitur yang sangat rumit maka kami mengeluarkan alat yang lebih berat. Misalnya, saat mendesain LINQ, salah satu orang kompiler dan salah satu orang IDE yang sama-sama memiliki latar belakang dalam teori parser membuat sendiri generator parser yang dapat menganalisis tata bahasa untuk mencari ambiguitas, dan kemudian memasukkan tata bahasa C # yang diusulkan untuk pemahaman kueri ke dalamnya. ; melakukan hal itu menemukan banyak kasus di mana kueri menjadi ambigu.
Atau, ketika kami melakukan inferensi tipe lanjutan pada lambda di C # 3.0 kami menulis proposal kami dan kemudian mengirimkannya ke Microsoft Research di Cambridge di mana tim bahasa di sana cukup baik untuk membuat bukti formal bahwa proposal inferensi tipe itu secara teoritis terdengar.
Tentu.
Dalam C # 1 jelas apa artinya. Itu sama dengan:
Artinya, ia memanggil G dengan dua argumen yang disebut bools. Dalam C # 2, itu bisa berarti apa yang dimaksud dalam C # 1, tetapi bisa juga berarti "berikan 0 ke metode umum F yang mengambil parameter tipe A dan B, dan kemudian meneruskan hasil dari F ke G". Kami menambahkan heuristik rumit ke parser yang menentukan kasus mana yang mungkin Anda maksudkan.
Demikian pula, pemerannya ambigu bahkan di C # 1.0:
Apakah itu "cast -x to T" atau "kurangi x dari T"? Sekali lagi, kami memiliki heuristik yang membuat tebakan bagus.
sumber
Karena begitulah bahasa itu ditentukan. Mereka tidak memberi nilai tambah, jadi mengapa menyertakannya?
Ini juga sangat mirip dengan array yang diketik implikasinya
Referensi: http://msdn.microsoft.com/en-us/library/ms364047%28VS.80%29.aspx
sumber
Ini dilakukan untuk menyederhanakan konstruksi objek. Desainer bahasa belum (sepengetahuan saya) secara khusus mengatakan mengapa mereka merasa ini berguna, meskipun secara eksplisit disebutkan di halaman Spesifikasi C # Versi 3.0 :
Saya kira mereka merasa tanda kurung, dalam hal ini, tidak diperlukan untuk menunjukkan maksud pengembang, karena penginisialisasi objek menunjukkan maksud untuk membangun dan menyetel properti objek sebagai gantinya.
sumber
Dalam contoh pertama Anda, kompilator menyimpulkan bahwa Anda memanggil konstruktor default (Spesifikasi Bahasa C # 3.0 menyatakan bahwa jika tidak ada tanda kurung yang disediakan, konstruktor default dipanggil).
Yang kedua, Anda secara eksplisit memanggil konstruktor default.
Anda juga dapat menggunakan sintaks itu untuk menyetel properti sambil secara eksplisit meneruskan nilai ke konstruktor. Jika Anda memiliki definisi kelas berikut:
Ketiga pernyataan itu valid:
sumber
Saya bukan Eric Lippert, jadi saya tidak bisa mengatakan dengan pasti, tetapi saya akan berasumsi itu karena tanda kurung kosong tidak diperlukan oleh kompilator untuk menyimpulkan konstruksi inisialisasi. Oleh karena itu menjadi informasi yang mubazir, dan tidak diperlukan.
sumber