Deklarasikan array const


458

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

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

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 };

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();

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


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

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.


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

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" };


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.


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


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.


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.


2

Saya percaya Anda hanya bisa membuatnya dibaca saja.


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


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.


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 };
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.