Deklarasikan array const

458

Apakah mungkin untuk menulis sesuatu yang mirip dengan yang berikut ini?

public const string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
Jaime Oro
sumber
statis dapat digunakan, string statis publik [] Judul = string baru [] {"Jerman", "Spanyol"};
Ray

Jawaban:

691

Ya, tetapi Anda harus mendeklarasikannya readonlydaripada const:

public static readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

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:

public enum Titles { German, Spanish, Corrects, Wrongs };
Cody Grey
sumber
115
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.

public readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
...
Titles[0] = "bla";

Pertimbangkan menggunakan enum, seperti yang disarankan Cody, atau IList.

public readonly IList<string> ITitles = new List<string> {"German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
Branimir
sumber
31
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).

Jairo
sumber
2
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.
waldrumpus
INI adalah satu-satunya jawaban yang benar.
Yousha Aleayoub
17

Sejak C # 6 Anda dapat menulis seperti:

public static string[] Titles => new string[] { "German", "Spanish", "Corrects", "Wrongs" };

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):

public static string[] Titles
{
    get { return new string[] { "German", "Spanish", "Corrects", "Wrongs" }; }
}

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:

public static IReadOnlyList<string> Titles { get; } = new string[] { "German", "Spanish", "Corrects", "Wrongs" };

Tapi, ini masih memiliki risiko untuk berubah, karena Anda masih bisa mengembalikannya ke string [] dan mengubah isinya, seperti:

((string[]) Titles)[1] = "French";
mjepson
sumber
1
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:

public readonly IReadOnlyList<string> Titles = new [] {"German", "Spanish", "Corrects", "Wrongs" };

Tersedia dalam .NET 4.5 dan lebih tinggi.

Richard Garside
sumber
6

Solusi .NET Framework v4.5 + yang meningkatkan jawaban tdbeckett :

using System.Collections.ObjectModel;

// ...

public ReadOnlyCollection<string> Titles { get; } = new ReadOnlyCollection<string>(
  new string[] { "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 kelas ReadOnlyCollection , bahkan tidak mendukung akses yang diindeks , membuatnya secara fundamental tidak cocok untuk menyediakan akses seperti array.)
mklement0
sumber
1
@ 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" };

ALZ
sumber
1
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

const string DefaultDistances = "5,10,15,20,25,30,40,50";
public static readonly string[] distances = DefaultDistances.Split(',');

Pendekatan ini memberi Anda konstanta yang dapat disimpan dalam konfigurasi dan dikonversi ke array saat diperlukan.

Alastair
sumber
8
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:

public readonly static ImmutableArray<string> Tiles = ImmutableArray.Create(new[] { "German", "Spanish", "Corrects", "Wrongs" });

Membutuhkan referensi System.Collections.Immutable NuGet

https://msdn.microsoft.com/en-us/library/mt452182(v=vs.111).aspx

shurik
sumber
3

Ini adalah cara untuk melakukan apa yang Anda inginkan:

using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;

public ReadOnlyCollection<string> Titles { get { return new List<string> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();}}

Ini sangat mirip dengan melakukan array readonly.

tdbeckett
sumber
8
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.

Roger Hill
sumber
2

Saya percaya Anda hanya bisa membuatnya dibaca saja.

skaz
sumber
2

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".

nemke
sumber
0

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.)

public static string[] Titles 
{
    get
    {
        return new string[] { "German", "Spanish", "Corrects", "Wrongs"};
    }
}

Tentu saja, ini tidak akan terlalu efisien karena array string baru dibuat setiap kali.

Kandang kelinci
sumber
0

Alternatif terbaik:

public static readonly byte[] ZeroHash = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Herman Schoenfeld
sumber