Alasannya adalah bahwa consthanya dapat diterapkan ke bidang yang nilainya diketahui pada waktu kompilasi. Penginisialisasi array yang Anda tunjukkan bukan ekspresi konstan dalam C #, sehingga menghasilkan kesalahan kompilator.
Mendeklarasikannya readonlymemecahkan masalah itu karena nilainya tidak diinisialisasi hingga waktu berjalan (meskipun dijamin telah diinisialisasi sebelum pertama kali array digunakan).
Bergantung pada apa yang akhirnya ingin Anda capai, Anda mungkin juga mempertimbangkan untuk mendeklarasikan enum:
Perhatikan bahwa array di sini tidak hanya bisa dibaca, tentu saja; Judul [2] = "Welsh"; akan bekerja dengan baik saat runtime
Marc Gravell
46
Anda mungkin ingin itu statis juga
tymtam
4
bagaimana dengan mendeklarasikan array "const" di dalam method body, bukan di class satu?
serhio
19
Maaf untuk suara turun, tetapi const juga menyiratkan statis. Mendeklarasikan array sebagai hanya baca tidak dekat dengan solusi. harus readonly staticmemiliki kemiripan semantik yang diminta.
Anton
3
@Anton, sudahkah Anda dan "pengikut" Anda menghapus downvote? Bagi saya statictidak diperlukan untuk membuatnya berfungsi, itu hanya menambah kemungkinan referensi Titlestanpa memiliki instance, tetapi menghapus kemungkinan untuk mengubah nilai untuk contoh yang berbeda (misalnya Anda dapat memiliki konstruktor dengan parameter tergantung pada mana Anda mengubah nilai readonlybidang itu).
Sinatr
57
Anda dapat mendeklarasikan array sebagai readonly, tetapi perlu diingat bahwa Anda dapat mengubah elemen readonlyarray.
Di .NET 4.5 dan yang lebih tinggi, Anda dapat mendeklarasikan daftar sebagai IReadOnlyList <string> alih-alih IList <string>.
Grzegorz Smulko
Untuk lebih jelasnya, Anda masih dapat mengubah nilai-nilai dalam IReadOnlyList (hanya saja tidak menambah atau menghapus elemen). Tapi ya, menyatakannya sebagai IReadOnlyList akan lebih baik daripada IList.
KevinVictor
Pertanyaannya adalah tentang constBUKAN readonly...
Yousha Aleayoub
51
Anda tidak dapat membuat array 'const' karena array adalah objek dan hanya dapat dibuat saat runtime dan entitas const diselesaikan pada waktu kompilasi.
Yang bisa Anda lakukan adalah mendeklarasikan array sebagai "readonly". Ini memiliki efek yang sama dengan const kecuali nilainya dapat diatur pada saat runtime. Ini hanya dapat ditetapkan sekali dan setelah itu nilai readonly (ie const).
Posting ini menyoroti mengapa array tidak dapat dideklarasikan sebagai konstanta
Radderz
1
Dimungkinkan untuk mendeklarasikan array yang konstan; masalahnya adalah menginisialisasi dengan nilai konstan. Satu-satunya contoh kerja yang terlintas dalam pikiran adalah const int[] a = null;yang tidak terlalu berguna, tetapi memang merupakan contoh konstanta array.
Ini akan membuat properti statis read-only, tetapi masih memungkinkan Anda untuk mengubah konten array yang dikembalikan, tetapi ketika Anda memanggil properti lagi, Anda akan mendapatkan array asli yang tidak diubah lagi.
Untuk klarifikasi, kode ini sama dengan (atau sebenarnya singkatan):
Harap dicatat bahwa ada kelemahan pada pendekatan ini: Array baru sebenarnya dipakai pada setiap referensi, jadi jika Anda menggunakan array yang sangat besar, ini mungkin bukan solusi yang paling efisien. Tetapi jika Anda menggunakan kembali array yang sama (dengan meletakkannya di atribut pribadi misalnya) itu lagi akan membuka kemungkinan untuk mengubah konten array.
Jika Anda ingin memiliki array (atau daftar) yang tidak dapat diubah, Anda juga dapat menggunakan:
Apa untungnya menggunakan properti daripada bidang dalam kasus ini?
nicolay.anykienko
2
Bidang tidak dapat mengembalikan objek baru pada setiap panggilan. Properti pada dasarnya adalah semacam "fungsi yang menyamar".
mjepson
1
Jika Anda merujuk ke opsi terakhir, itu bisa dilakukan menggunakan bidang atau properti, tetapi karena bersifat publik, saya lebih suka Properti. Saya tidak pernah menggunakan bidang publik sejak diperkenalkannya Properti.
mjepson
1
Ada kelemahan lain dari pendekatan 1: Anda tidak akan mendapatkan kesalahan kompilasi jika Anda menetapkan untuk Titles[0], misalnya - pada dasarnya, upaya penugasan diam-diam diabaikan. Dikombinasikan dengan inefisiensi menciptakan array setiap waktu, saya bertanya-tanya apakah pendekatan ini bahkan layak ditampilkan. Sebaliknya, pendekatan ke-2 adalah efisien, dan Anda harus keluar dari jalan untuk mengalahkan kekekalan.
mklement0
6
Jika Anda mendeklarasikan array di belakang antarmuka IReadOnlyList, Anda mendapatkan array konstan dengan nilai konstan yang dideklarasikan pada saat runtime:
using System.Collections.ObjectModel;// ...publicReadOnlyCollection<string>Titles{get;}=newReadOnlyCollection<string>(newstring[]{"German","Spanish","Corrects","Wrongs"});
Catatan: Mengingat bahwa kumpulan itu konstan secara konseptual, mungkin masuk akal staticuntuk menyatakannya di tingkat kelas .
Di atas:
Menginisialisasi bidang dukungan implisit properti sekali dengan array.
Perhatikan bahwa { get; }- yaitu, mendeklarasikan hanya pengambil properti - adalah yang membuat properti itu sendiri hanya baca-saja (mencoba untuk menggabungkan readonlydengan { get; }sebenarnya adalah kesalahan sintaksis).
Atau, Anda bisa menghilangkan { get; }dan menambahkan readonlyuntuk membuat bidang alih-alih properti, seperti dalam pertanyaan, tetapi mengekspos anggota data publik sebagai properti daripada bidang adalah kebiasaan yang baik untuk dibentuk.
Membuat struktur mirip array (memungkinkan akses yang diindeks ) yang benar-benar dan kuat hanya-baca (konseptual konstan, sekali dibuat), keduanya berkenaan dengan:
mencegah modifikasi koleksi secara keseluruhan (seperti dengan menghapus atau menambahkan elemen, atau dengan menetapkan koleksi baru ke variabel).
mencegah modifikasi elemen individu .
(Bahkan tidak langsung modifikasi tidak mungkin - tidak seperti dengan IReadOnlyList<T>solusi, di mana sebuah (string[])cor dapat digunakan untuk mendapatkan akses tulis ke unsur-unsur , seperti yang ditunjukkan pada mjepsen ini jawaban yang membantu .
Kerentanan yang sama berlaku untuk para IReadOnlyCollection<T>antarmuka , yang, meskipun kesamaan nama ke kelasReadOnlyCollection , bahkan tidak mendukung akses yang diindeks , membuatnya secara fundamental tidak cocok untuk menyediakan akses seperti array.)
@ portb: Sayangnya, IReadOnlyCollectiontidak mendukung akses yang diindeks, sehingga tidak dapat digunakan di sini. Selain itu, seperti IReadOnlyList(yang memang memiliki akses terindeks), ia rentan terhadap manipulasi elemen dengan kembali ke string[]. Dengan kata lain: ReadOnlyCollection(yang Anda tidak bisa melemparkan array string ke) adalah solusi yang paling kuat. Tidak menggunakan pengambil adalah sebuah opsi (dan saya telah memperbarui jawaban untuk mencatatnya), tetapi dengan data publik mungkin lebih baik tetap menggunakan properti.
mklement0
5
Untuk kebutuhan saya, saya mendefinisikan staticarray, bukannya tidak mungkin constdan berfungsi:
public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
Cukup menghapus constdari contoh OP juga berfungsi, tetapi itu (atau jawaban Anda) memungkinkan untuk mengubah keduanya: Titlesinstance dan nilai apa pun. Jadi apa gunanya jawaban ini?
Sinatr
@ Sinatr, saya menjawab ini 3 tahun yang lalu, ketika saya bekerja di C #. Saya meninggalkannya, sekarang saya di dunia Jawa. Mungkin saya lupa menambahkanreadonly
ALZ
Setelah berpikir dua kali, jawaban Anda adalah cara langsung membuat kode OP berfungsi , tanpa const/ readonlypertimbangan, membuatnya berfungsi (seperti jika constitu adalah kesalahan sintaksis). Bagi sebagian orang itu sepertinya jawaban yang berharga (mungkin mereka juga mencoba menggunakan constsecara tidak sengaja?).
Sinatr
5
Anda bisa mengambil pendekatan yang berbeda: mendefinisikan string konstan untuk mewakili array Anda dan kemudian membagi string menjadi sebuah array ketika Anda membutuhkannya, misalnya
Saya pikir biaya melakukan split jauh melampaui manfaat yang dibuat dengan mendefinisikan const. Tapi +1 untuk pendekatan yang unik dan pemikiran di luar kotak! ;)
Radderz
Saya akan memposting solusi yang sama dan kemudian melihat ini, bertentangan dengan pernyataan yang keras dan negatif, ini sebenarnya cocok untuk skenario saya, di mana saya harus memberikan konstanta ke atribut, dan kemudian saya membagi nilai dalam atribut constructor ke dapatkan apa yang saya butuhkan. dan saya tidak melihat alasan mengapa ia akan memiliki biaya kinerja karena atribut tidak dibuat untuk setiap instance.
Kalpesh Popat
4
Demi kelengkapan, sekarang kami juga memiliki ImmutableArays yang kami miliki. Ini harus benar-benar abadi:
Ini adalah cara untuk melakukan apa yang Anda inginkan:
using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;publicReadOnlyCollection<string>Titles{get{returnnewList<string>{"German","Spanish","Corrects","Wrongs"}.AsReadOnly();}}
Anda bisa melakukannya sebagai public static readonly ReadOnlyCollection<String> Titles = new List<String> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();; tidak perlu membuat ulang daftar di setiap pengambilan jika Anda menjadikannya ReadOnlyCollection.
Nyerguds
3
Ini satu-satunya jawaban yang benar. Saat ini Anda tidak dapat melakukan ini.
Semua jawaban lain menyarankan menggunakan variabel read-only statis yang mirip dengan , tetapi tidak sama dengan konstanta. Konstanta sulit dikodekan ke dalam rakitan. Variabel read only statis dapat disetel sekali, mungkin sebagai objek diinisialisasi.
Ini kadang-kadang dipertukarkan, tetapi tidak selalu.
Array mungkin salah satu dari hal-hal yang hanya dapat dievaluasi saat runtime. Konstanta harus dievaluasi pada waktu kompilasi. Coba gunakan "readonly" alih-alih "const".
Sebagai alternatif, untuk mengatasi masalah elemen-dapat-dimodifikasi dengan array hanya baca, Anda dapat menggunakan properti statis sebagai gantinya. (Elemen individu masih dapat diubah, tetapi perubahan ini hanya akan dilakukan pada salinan lokal array.)
Jawaban:
Ya, tetapi Anda harus mendeklarasikannya
readonly
daripadaconst
:Alasannya adalah bahwa
const
hanya dapat diterapkan ke bidang yang nilainya diketahui pada waktu kompilasi. Penginisialisasi array yang Anda tunjukkan bukan ekspresi konstan dalam C #, sehingga menghasilkan kesalahan kompilator.Mendeklarasikannya
readonly
memecahkan masalah itu karena nilainya tidak diinisialisasi hingga waktu berjalan (meskipun dijamin telah diinisialisasi sebelum pertama kali array digunakan).Bergantung pada apa yang akhirnya ingin Anda capai, Anda mungkin juga mempertimbangkan untuk mendeklarasikan enum:
sumber
readonly static
memiliki kemiripan semantik yang diminta.static
tidak diperlukan untuk membuatnya berfungsi, itu hanya menambah kemungkinan referensiTitles
tanpa memiliki instance, tetapi menghapus kemungkinan untuk mengubah nilai untuk contoh yang berbeda (misalnya Anda dapat memiliki konstruktor dengan parameter tergantung pada mana Anda mengubah nilaireadonly
bidang itu).Anda dapat mendeklarasikan array sebagai
readonly
, tetapi perlu diingat bahwa Anda dapat mengubah elemenreadonly
array.Pertimbangkan menggunakan enum, seperti yang disarankan Cody, atau IList.
sumber
const
BUKANreadonly
...Anda tidak dapat membuat array 'const' karena array adalah objek dan hanya dapat dibuat saat runtime dan entitas const diselesaikan pada waktu kompilasi.
Yang bisa Anda lakukan adalah mendeklarasikan array sebagai "readonly". Ini memiliki efek yang sama dengan const kecuali nilainya dapat diatur pada saat runtime. Ini hanya dapat ditetapkan sekali dan setelah itu nilai readonly (ie const).
sumber
const int[] a = null;
yang tidak terlalu berguna, tetapi memang merupakan contoh konstanta array.Sejak C # 6 Anda dapat menulis seperti:
Lihat juga: C #: C # 6.0 yang Baru dan yang Disempurnakan (khususnya bab "Fungsi dan Properti yang Berekspresi")
Ini akan membuat properti statis read-only, tetapi masih memungkinkan Anda untuk mengubah konten array yang dikembalikan, tetapi ketika Anda memanggil properti lagi, Anda akan mendapatkan array asli yang tidak diubah lagi.
Untuk klarifikasi, kode ini sama dengan (atau sebenarnya singkatan):
Harap dicatat bahwa ada kelemahan pada pendekatan ini: Array baru sebenarnya dipakai pada setiap referensi, jadi jika Anda menggunakan array yang sangat besar, ini mungkin bukan solusi yang paling efisien. Tetapi jika Anda menggunakan kembali array yang sama (dengan meletakkannya di atribut pribadi misalnya) itu lagi akan membuka kemungkinan untuk mengubah konten array.
Jika Anda ingin memiliki array (atau daftar) yang tidak dapat diubah, Anda juga dapat menggunakan:
Tapi, ini masih memiliki risiko untuk berubah, karena Anda masih bisa mengembalikannya ke string [] dan mengubah isinya, seperti:
sumber
Titles[0]
, misalnya - pada dasarnya, upaya penugasan diam-diam diabaikan. Dikombinasikan dengan inefisiensi menciptakan array setiap waktu, saya bertanya-tanya apakah pendekatan ini bahkan layak ditampilkan. Sebaliknya, pendekatan ke-2 adalah efisien, dan Anda harus keluar dari jalan untuk mengalahkan kekekalan.Jika Anda mendeklarasikan array di belakang antarmuka IReadOnlyList, Anda mendapatkan array konstan dengan nilai konstan yang dideklarasikan pada saat runtime:
Tersedia dalam .NET 4.5 dan lebih tinggi.
sumber
Solusi .NET Framework v4.5 + yang meningkatkan jawaban tdbeckett :
Catatan: Mengingat bahwa kumpulan itu konstan secara konseptual, mungkin masuk akal
static
untuk menyatakannya di tingkat kelas .Di atas:
Menginisialisasi bidang dukungan implisit properti sekali dengan array.
Perhatikan bahwa
{ get; }
- yaitu, mendeklarasikan hanya pengambil properti - adalah yang membuat properti itu sendiri hanya baca-saja (mencoba untuk menggabungkanreadonly
dengan{ get; }
sebenarnya adalah kesalahan sintaksis).Atau, Anda bisa menghilangkan
{ get; }
dan menambahkanreadonly
untuk membuat bidang alih-alih properti, seperti dalam pertanyaan, tetapi mengekspos anggota data publik sebagai properti daripada bidang adalah kebiasaan yang baik untuk dibentuk.Membuat struktur mirip array (memungkinkan akses yang diindeks ) yang benar-benar dan kuat hanya-baca (konseptual konstan, sekali dibuat), keduanya berkenaan dengan:
(Bahkan tidak langsung modifikasi tidak mungkin - tidak seperti dengan
IReadOnlyList<T>
solusi, di mana sebuah(string[])
cor dapat digunakan untuk mendapatkan akses tulis ke unsur-unsur , seperti yang ditunjukkan pada mjepsen ini jawaban yang membantu .Kerentanan yang sama berlaku untuk para
IReadOnlyCollection<T>
antarmuka , yang, meskipun kesamaan nama ke kelasReadOnlyCollection
, bahkan tidak mendukung akses yang diindeks , membuatnya secara fundamental tidak cocok untuk menyediakan akses seperti array.)sumber
IReadOnlyCollection
tidak mendukung akses yang diindeks, sehingga tidak dapat digunakan di sini. Selain itu, sepertiIReadOnlyList
(yang memang memiliki akses terindeks), ia rentan terhadap manipulasi elemen dengan kembali kestring[]
. Dengan kata lain:ReadOnlyCollection
(yang Anda tidak bisa melemparkan array string ke) adalah solusi yang paling kuat. Tidak menggunakan pengambil adalah sebuah opsi (dan saya telah memperbarui jawaban untuk mencatatnya), tetapi dengan data publik mungkin lebih baik tetap menggunakan properti.Untuk kebutuhan saya, saya mendefinisikan
static
array, bukannya tidak mungkinconst
dan berfungsi:public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
sumber
const
dari contoh OP juga berfungsi, tetapi itu (atau jawaban Anda) memungkinkan untuk mengubah keduanya:Titles
instance dan nilai apa pun. Jadi apa gunanya jawaban ini?readonly
const
/readonly
pertimbangan, membuatnya berfungsi (seperti jikaconst
itu adalah kesalahan sintaksis). Bagi sebagian orang itu sepertinya jawaban yang berharga (mungkin mereka juga mencoba menggunakanconst
secara tidak sengaja?).Anda bisa mengambil pendekatan yang berbeda: mendefinisikan string konstan untuk mewakili array Anda dan kemudian membagi string menjadi sebuah array ketika Anda membutuhkannya, misalnya
Pendekatan ini memberi Anda konstanta yang dapat disimpan dalam konfigurasi dan dikonversi ke array saat diperlukan.
sumber
Demi kelengkapan, sekarang kami juga memiliki ImmutableArays yang kami miliki. Ini harus benar-benar abadi:
Membutuhkan referensi System.Collections.Immutable NuGet
https://msdn.microsoft.com/en-us/library/mt452182(v=vs.111).aspx
sumber
Ini adalah cara untuk melakukan apa yang Anda inginkan:
Ini sangat mirip dengan melakukan array readonly.
sumber
public static readonly ReadOnlyCollection<String> Titles = new List<String> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
; tidak perlu membuat ulang daftar di setiap pengambilan jika Anda menjadikannya ReadOnlyCollection.Ini satu-satunya jawaban yang benar. Saat ini Anda tidak dapat melakukan ini.
Semua jawaban lain menyarankan menggunakan variabel read-only statis yang mirip dengan , tetapi tidak sama dengan konstanta. Konstanta sulit dikodekan ke dalam rakitan. Variabel read only statis dapat disetel sekali, mungkin sebagai objek diinisialisasi.
Ini kadang-kadang dipertukarkan, tetapi tidak selalu.
sumber
Saya percaya Anda hanya bisa membuatnya dibaca saja.
sumber
Array mungkin salah satu dari hal-hal yang hanya dapat dievaluasi saat runtime. Konstanta harus dievaluasi pada waktu kompilasi. Coba gunakan "readonly" alih-alih "const".
sumber
Sebagai alternatif, untuk mengatasi masalah elemen-dapat-dimodifikasi dengan array hanya baca, Anda dapat menggunakan properti statis sebagai gantinya. (Elemen individu masih dapat diubah, tetapi perubahan ini hanya akan dilakukan pada salinan lokal array.)
Tentu saja, ini tidak akan terlalu efisien karena array string baru dibuat setiap kali.
sumber
Alternatif terbaik:
sumber