Tidak dapat menggunakan array "inline" di C #?


92

Bayangkan Anda memiliki ini di suatu tempat

public static T AnyOne<T>(this T[] ra) where T:class
    {
    int k = ra.Length;
    int r = Random.Range(0,k);
    return ra[r];
    }

atau bahkan hanya ini

public static string OneOf(this string[] strings)
    {
    return "a";
    }

Maka, tentu saja Anda bisa melakukan ini ...

string[] st = {"a","b","c"};
string letter = st.AnyOne();

... yang bagus. TAPI. Tampaknya Anda TIDAK dapat melakukan ini:

string letter = {"a","b","c"}.AnyOne();

atau mungkin ini

string letter = ( {"a","b","c"} ).AnyOne();

atau apa pun yang saya coba.

Faktanya (1) mengapa seseorang tidak bisa melakukan itu? dan (2) apakah saya melewatkan sesuatu, bagaimana Anda akan melakukannya jika ada cara?


5
Saya tidak yakin pertanyaan duplikatnya sesuai, OP tidak menanyakan tentang penginisialisasi array, tetapi mengapa kompilator tidak akan mengenali objek sebagai array sampai ia ditugaskan.
Ron Beyer

4
Saya tidak terbiasa dengan terminologi C #, tapi saya yakin ini lebih sering disebut literal atau literal array daripada sebaris .
chi

3
Elemen sintaksis tersebut adalah penginisialisasi array atau penginisialisasi koleksi , bergantung pada konteks penggunaannya. Dalam kedua kasus itu tidak diklasifikasikan sebagai ekspresi .
Eric Lippert

Jawaban:


133

Anda harus membuat array terlebih dahulu, menggunakan new[].

string letter = (new[] {"a","b","c"}).AnyOne();

Seperti yang disebutkan @hvd, Anda dapat melakukan ini tanpa tanda kurung (..), saya menambahkan tanda kurung karena menurut saya itu lebih mudah dibaca.

string letter = new[] {"a","b","c"}.AnyOne();

Dan Anda dapat menentukan tipe datanya new string[]seperti pada jawaban lain yang telah disebutkan.


Anda tidak bisa begitu saja melakukannya {"a","b","c"}, karena Anda dapat menganggapnya sebagai cara untuk mengisi array, bukan membuatnya.

Alasan lain adalah kompilator akan bingung, tidak tahu harus membuat apa, misalnya, a string[]{ .. }atau a List<string>{ .. }.

Menggunakan new[]kompiler saja dapat mengetahui dengan tipe data ( ".."), antara {..}, apa yang Anda inginkan ( string). Bagian yang penting adalah [], itu artinya Anda menginginkan sebuah array.

Anda bahkan tidak dapat membuat array kosong dengan new[].

string[] array = new []{ }; // Error: No best type found for implicity-typed array

13
Anda tidak membutuhkan tanda kurung itu. string letter = new[] {"a","b","c"}.AnyOne();baik-baik saja. Jika Anda menginginkannya, jika menurut Anda itu lebih mudah dibaca dengan tanda kurung, itu valid, tetapi dalam hal ini saya pikir paling tidak perlu disebutkan bahwa itu adalah pilihan sadar Anda, bahwa itu tidak dipaksa oleh bahasa.

Saya tahu tentang sintaks baru [] {1,2}, tetapi apakah ada sintaks yang lebih sederhana? Sesuatu seperti [1, 2]?
seguso

51

(1) mengapa seseorang tidak bisa melakukan itu? {"a","b","c"}.AnyOne();

Garis ini:

string[] st = {"a","b","c"};

adalah kependekan dari ekspresi pembuatan larik yang setara (di bawah ILSpy )

string[] st = new string[]  {"a","b","c"};

Ini string[] st = {"a","b","c"} hanya dapat digunakan pada saat deklarasi , Anda tidak dapat menggunakannya di tempat lain, Anda bahkan tidak dapat melakukan:

string[] st;
st = {"a", "b", "c"}; //Error

Ini dijelaskan di bawah Bagian 7.6.10.4 untuk ekspresi Penciptaan Array dalam spesifikasi bahasa C #.

Jadi ini "{"a", "b", "c"}"saja tanpa penggunaan dalam deklarasi tidak ada artinya. Karenanya Anda tidak dapat menggunakannya dengan metode ekstensi Anda, karena metode ekstensi Anda beroperasi pada array.

(2) apakah saya melewatkan sesuatu, bagaimana Anda akan melakukannya jika ada cara?

Sudah disebutkan dalam jawaban @adricadar , Anda bisa melakukan:

(new[] {"a","b","c"}).AnyOne();

atau

(new string[] {"a","b","c"}).AnyOne();

48

Saya menolak pertanyaan "mengapa tidak" karena pertama, jawabannya hampir tidak pernah memuaskan - Anda sudah mendapatkan jawaban "fiturnya tidak sesuai dengan yang Anda inginkan karena spesifikasinya tidak menyatakan apa yang Anda inginkan" , yang menurut saya bukanlah jawaban yang memuaskan. Kedua, tim desain tidak harus membenarkan mengapa dunia tidak seperti yang Anda inginkan; fitur tidak ada secara gratis dan kemudian dirancang dari bahasa tersebut; sebaliknya, fitur harus dijustifikasi terlebih dahulu, dan kemudian didesain.

Jadi, mari kita coba membuat pertanyaan "mengapa tidak" Anda sedikit lebih tajam. Fitur yang ada adalah "penginisialisasi array dapat digunakan (a) di sisi kanan yang sama dalam inisialisasi atau (b) di sebelah kanan konstruksi objek tipe array." Fitur yang diusulkan adalah: "penginisialisasi larik juga dapat digunakan sebagai ekspresi". Pertanyaannya adalah "kritik apa yang akan Eric buat tentang fitur yang diusulkan?"

Kritik pertama yang akan saya buat adalah tidak jelasnya jenis ekspresi tersebut. Dalam penginisialisasi variabel Anda memiliki tipe variabel dan dalam ekspresi pembuatan objek Anda memiliki tipe objek; dari keduanya, kita dapat menyimpulkan jenis array yang dibangun. Tanpa petunjuk apa pun, jenis apa yang harus kita simpulkan?

Di C # 1.0, ketika fitur ini ditambahkan, ada total inferensi tipe nol yang dibuat dalam bahasa tersebut. Prinsip desain pada masa awal C # adalah "tidak ada kejutan", dan kompilernya tidak "terlalu pintar". Jika pengembang bermaksud ekspresi menjadi tipe tertentu maka tipe itu harus dalam beberapa cara jelas dalam ekspresi. Saat Anda berkata

new double[] { 1, 2, 3.4 }

cukup jelas jenis apa yang dimaksudkan. Demikian pula

new Animal[] { cat, dog, null }

Fitur yang diusulkan melanggar prinsip ini. Ekspresi harus memiliki tipe, tetapi sama sekali tidak jelas apa tipe argumennya

M({cat, dog, null})

Selain itu: Misalkan kita memiliki dua kelebihan M, salah satunya mengambil array Animaldan satu lagi mengambil array IPet. Beban berlebih mana Myang berlaku? Apakah salah satu konversi lebih baik dari yang lain? Jenis elemennya adalah Catdan Dog; apakah masuk akal untuk menyimpulkan jenis yang bahkan tidak muncul di sana? Ini semua adalah pertanyaan yang harus dipertimbangkan oleh tim desain, dan ini adalah pertanyaan yang tidak memiliki jawaban yang jelas. Fitur yang diusulkan membawa kita ke perairan dalam dalam waktu yang cukup singkat.

Sekarang, C # 3.0 memecahkan masalah ini karena C # 3.0 menambahkan banyak fitur di mana kompilator menyimpulkan jenis atas nama pengembang. Prinsip sebelumnya tentang "tidak ada kejutan" dan "aturan sederhana" bertentangan dengan prinsip desain lain yang diperlukan untuk membuat LINQ berfungsi. Haruskah fitur yang Anda usulkan telah ditambahkan di C # 3.0?

Bisa saja. Fitur yang sebenarnya ditambahkan di C # 3.0 adalah:

new[] { x, y, z }

menyimpulkan tipe array menggunakan algoritme: ambil ekspresi untuk elemen yang memiliki tipe, tentukan tipe mana yang merupakan tipe paling umum unik yang semua ekspresi lainnya dapat diubah, dan jika tipe seperti itu ada, pilih itu. Jika tidak menghasilkan kesalahan,

Fitur itu bisa lebih santai untuk dijadikan new[]opsional. Ini belum selesai.

Sekarang, jika Anda telah meminta saya dalam jangka waktu C # 3.0 untuk mengkritik fitur yang diusulkan, saya akan menunjukkan bahwa (1) compiler C # 3.0 sudah berada dalam bahaya besar untuk menyelipkan jadwal untuk seluruh rilis, jadi jangan menambahkan lagi desain, implementasi, dan beban pengujian untuk fitur yang benar-benar tidak perlu yang menghemat enam kali penekanan tombol, dan (2) C # 3.0 juga menambahkan penginisialisasi koleksi:

new List<int>() { 10, 20, 30 }

kenapa harus {10, 20, 30}otomatis jadi array ? Mengapa tidak menjadi List<int>? Atau salah satu dari sejumlah tipe lainnya? Mengapa bias terhadap array? Ingat, begitu kita memilih untuk mengabadikan sintaks untuk array, kita terjebak dengannya selamanya . Ini mungkin tidak akan pernah apa pun, sehingga fitur yang diusulkan tidak hanya tidak perlu, juga mencegah kemungkinan fitur masa depan yang tampaknya masuk akal.

Kesimpulannya: fitur yang diusulkan secara langsung melanggar beberapa prinsip desain C # 1.0. Ia menambahkan apa-apa selain beban yang tidak perlu ke C # 3.0. Di semua versi bahasa sejak C # 3.0, fitur yang diusulkan tidak memiliki argumen yang baik untuk merekomendasikan menghabiskan waktu, tenaga dan uang untuk itu daripada banyak fitur lain yang lebih layak.

Oleh karena itu, tidak ada fitur seperti itu.


Heh, Anda perlu mendapatkan kaos dengan cetakan "dunia tidak seperti yang Anda inginkan" tercetak di atasnya :)
slugster

6
@ JoeBlow: Pertama, Anda sangat disambut. Mengenai "mengapa tidak" - komentar Anda menggambarkan masalah dengan baik. Ketika beberapa orang mengajukan pertanyaan "mengapa", mereka mencari pembenaran yang logis . Beberapa orang mencari pembenaran pragmatis . Dan Anda tampaknya sedang mencari baris spesifikasi yang menjelaskan aturan tersebut . Sangat tidak jelas sehingga sangat sulit untuk membuat jawaban yang baik yang menargetkan pertanyaan sebenarnya di benak penanya. Pertanyaan "mengapa tidak" menjadi lebih buruk karena merupakan pertanyaan samar tentang hal-hal yang bahkan tidak ada .
Eric Lippert

3
@EricLippert Ini bahkan lebih buruk daripada hanya pertanyaan tentang hal-hal yang _might_ ada : Jika Anda mengerjakan perangkat lunak dengan tim, seluruh tim menghabiskan setiap hari sepanjang tahun untuk memikirkan fitur dan menyeimbangkan konsekuensinya. Keputusan dibuat. Permintaan fitur dan 'mengapa' meminta pembenaran. Namun, mengapa tidak menyiratkan bahwa seseorang hanya ingin sesuatu dilakukan, yang pada dasarnya mempertanyakan penilaian tim itu sendiri. Lebih buruk lagi, orang yang menanyakan pertanyaan mengapa tidak biasanya tahu sedikit tentang subjek tersebut. Karena itu, saya pikir menolak pertanyaan mengapa tidak sepenuhnya adil. Kerja bagus, IMO.
atlaste
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.