Baca statis vs const

1387

Saya sudah membaca tentang constdan static readonlybidang. Kami memiliki beberapa kelas yang hanya berisi nilai konstan. Digunakan untuk berbagai hal di dalam sistem kami. Jadi saya bertanya-tanya apakah pengamatan saya benar:

Haruskah nilai konstan semacam ini selalu static readonlyuntuk semua yang bersifat publik? Dan hanya digunakan constuntuk nilai internal / dilindungi / pribadi?

Apa yang kamu sarankan? Haruskah saya bahkan mungkin tidak menggunakan static readonlybidang, melainkan menggunakan properti mungkin?

Svish
sumber
5
Berikut ini adalah satu kasus yang sangat menarik yang saya temukan dalam mendukung static readonly: coba gunakan const di dalam IEnumeratoryang akan memicu unrecheable yield dan Anda akan mendapatkan "kesalahan kompiler internal" yang ditakuti . Saya tidak menguji kode di luar Unity3D, tapi saya percaya ini adalah bug mono atau .NET . Meskipun demikian, ini adalah masalah c # .
cregox
8
Perbedaan lain adalah bahwa Anda dapat menggunakan string const dalam sebuah switch, tetapi bukan string readonly statis
flagg19
7
static readonlytidak dapat digunakan dalam switch-casepernyataan sebagai casevariabel, constdiperlukan untuk tujuan ini.
Mostafiz Rahman
3
static readonlytidak dapat digunakan sebagai parameter atribut juga
Dread Boy

Jawaban:

940

public static readonlyladang sedikit tidak biasa; public staticproperti (dengan hanya a get) akan lebih umum (mungkin didukung oleh private static readonlybidang).

constnilai dibakar langsung ke situs panggilan; ini bermata dua:

  • tidak berguna jika nilainya diambil pada saat runtime, mungkin dari config
  • jika Anda mengubah nilai const, Anda perlu membangun kembali semua klien
  • tetapi bisa lebih cepat, karena menghindari panggilan metode ...
  • ... yang kadang-kadang mungkin telah diuraikan oleh JIT

Jika nilainya tidak akan pernah berubah, maka const baik-baik saja - Zerodll buat konstanta yang masuk akal; p Selain itu, staticproperti lebih umum.

Marc Gravell
sumber
13
Mengapa properti lebih dari satu bidang? Jika ini adalah kelas yang tidak berubah, saya tidak melihat perbedaan.
Michael Hedgpeth
73
@Michael - alasan yang sama seperti biasanya; itu menyembunyikan implementasinya. Anda mungkin (kemudian) menemukan bahwa Anda perlu dimuat dengan malas, berbasis konfigurasi, fasad, atau apa pun. Pada kenyataannya, baik sering baik-baik saja ...
Marc Gravell
42
@CoffeeAddict menurut definisi, konstanta tidak menarik nilai dari file konfigurasi; itu dibakar sebagai literal pada waktu kompilasi. Satu-satunya cara Anda dapat menggunakan konstanta saat runtime adalah melalui refleksi atas bidang. Kapan pun Anda mencoba menggunakannya, kompiler yang sudah menggantikan penggunaan konstan Anda untuk penggunaan literal ; yaitu jika suatu metode dalam kode Anda menggunakan 6 konstanta, dan Anda memeriksanya sebagai IL, tidak akan ada lagi penyebutan konstan; nilai literal hanya akan dimuat in-situ
Marc Gravell
37
@MarcGravell - PERHATIAN: readonlybidang tidak dapat digunakan dalam pernyataan switch / case, sebagai gantinya Anda membutuhkannya const.
Luciano
7
@didibus Mengubah bidang ke properti, pada kenyataannya, memecah API. Bidang dalam C # secara efektif bertindak seperti variabel, sementara properti di C # adalah penolong sintaksis untuk menulis metode pengambil dan / atau metode penyetel. Perbedaan ini penting ketika majelis lain terlibat. Jika Anda mengubah bidang ke properti, dan majelis lain bergantung pada bidang ini, maka majelis lain harus dikompilasi ulang.
Stephen Booher
237

Saya akan menggunakan static readonlyjika Konsumen berada dalam majelis yang berbeda. Memiliki constdan Konsumen dalam dua majelis berbeda adalah cara yang bagus untuk menembak diri sendiri .

Michael Stum
sumber
5
Jadi saya pikir beberapa telah disebutkan atau disinggung, mungkin bijaksana untuk hanya menggunakan const untuk nilai-nilai yang benar-benar dikenal konstanta jika mereka dipublikasikan jika tidak mereka harus dicadangkan untuk lingkup akses internal, dilindungi, atau pribadi.
jpierson
1
@ Do Alasan itu masih ada adalah karena itu bukan masalah per se - itu adalah sesuatu yang harus diperhatikan, tetapi kemampuan untuk menyejajarkan konstanta lintas batas perakitan adalah hal yang baik untuk kinerja. Ini hanya masalah pemahaman bahwa "konstan" berarti "tidak akan pernah berubah".
Michael Stum
1
@MichaelStum Ok, saya seharusnya tidak menyebutnya "masalah". Dalam pekerjaan saya, saya memiliki const dan membaginya di seluruh majelis tetapi saya mengkompilasi ulang untuk setiap penyebaran atau pengiriman kode. Namun demikian, fakta ini sangat layak untuk dicatat.
Dio Phung
1
Jadi, secara umum, internal constatau public static readonlytergantung pada visibilitas yang diinginkan.
Iiridayn
2
@Iiridayn Ya, itu bukan cara yang buruk untuk melihatnya. Ada beberapa kasus tepi yang perlu dipertimbangkan (misalnya, jika menggunakan Refleksi, atau jika nilai diperlukan pada atribut), dan ada kegunaan yang valid untuk public const(misalnya, apa pun bagian dari standar. Setiap kali saya bekerja dengan XML, ada file namespaces dengan sekelompok public const string.) Tetapi secara umum, public consthanya boleh digunakan setelah mempertimbangkan implikasinya dengan benar.
Michael Stum
200

Beberapa hal yang lebih relevan untuk dicatat:

const int a

  • harus diinisialisasi.
  • inisialisasi harus pada waktu kompilasi .

hanya baca int

  • dapat menggunakan nilai default, tanpa menginisialisasi.
  • inisialisasi dapat dilakukan pada waktu berjalan (Edit: hanya dalam konstruktor).
Peter
sumber
39
dalam ctorsatu - satunya.
Amit Kumar Ghosh
1
Tidak hanya di dalam konstruktor tetapi juga di dalam deklarasi ( docs.microsoft.com/en-us/dotnet/csharp/language-reference/… ).
deChristo
176

Ini hanya pelengkap jawaban lainnya. Saya tidak akan mengulanginya (sekarang empat tahun kemudian).

Ada situasi di mana a constdan non-const memiliki semantik yang berbeda. Sebagai contoh:

const int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

mencetak True, sedangkan:

static readonly int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

menulis False.

Alasannya adalah bahwa metode ini x.Equalsmemiliki dua kelebihan, satu mengambil short( System.Int16) dan satu mengambil object( System.Object). Sekarang pertanyaannya adalah apakah satu atau keduanya berlaku dengan yargumen saya .

Ketika ykonstanta waktu kompilasi (literal), constkasus, menjadi penting bahwa memang ada konversi implisit dari int ke short asalkan intkonstanta, dan asalkan kompiler C # memverifikasi bahwa nilainya berada dalam kisaran a short( yang mana 42). Lihat Konversi ekspresi konstan yang tersirat dalam Spesifikasi Bahasa C #. Jadi kedua kelebihan harus dipertimbangkan. Overload Equals(short)lebih disukai (setiap shortadalah object, tetapi tidak semua objectadalah short). Jadi ydikonversi ke short, dan kelebihan itu digunakan. Kemudian Equalsmembandingkan dua shortnilai identik, dan itu memberi true.

Bila ytidak konstan, tidak ada implisit konversi dari intke shortada. Itu karena secara umum intmungkin terlalu besar untuk dimasukkan ke dalam short. ( Konversi eksplisit memang ada, tetapi saya tidak mengatakannya Equals((short)y), jadi itu tidak relevan.) Kita melihat bahwa hanya satu kelebihan yang berlaku, yang Equals(object)satu. Jadi ykotak untuk object. Maka Equalsakan membandingkan a System.Int16ke a System.Int32, dan karena tipe run-time bahkan tidak setuju, itu akan menghasilkan false.

Kami menyimpulkan bahwa dalam beberapa kasus (jarang), mengubah anggota consttipe menjadi static readonlybidang (atau sebaliknya, jika memungkinkan) dapat mengubah perilaku program.

Jeppe Stig Nielsen
sumber
17
Tambahan yang bagus untuk jawaban yang diterima. Saya ingin menambahkan bahwa konversi yang tepat dari tipe data dan pedoman serupa lainnya (seperti try catches dll) harus menjadi pokok dari programmer yang berpengalaman dan tidak diserahkan kepada kompiler. Meskipun demikian, saya belajar sesuatu yang baru dari sini. Terima kasih.
Uknight
Wow, saya telah memprogram dalam C # untuk waktu yang lama dan saya tidak akan pernah menduga bahwa sebuah int dalam rentang pendek dapat secara implisit dikonversi menjadi pendek. Saya harus mengatakan itu agak aneh. Saya suka C # tetapi ini inkonsistensi aneh yang tampaknya tidak menambah banyak nilai tetapi menambah banyak kekuatan otak yang diperlukan untuk terus-menerus dapat mengganggu, terutama untuk pemula.
Mike Marynowski
@ MikeMarynowski Cukup benar. Tapi saya pikir mereka membuat aturan itu (antara lain alasan) untuk membuat pernyataan itu short x = 42;sah. Karena di sana Anda memiliki int, yaitu literal 42, yang secara implisit berubah menjadi short x. Tapi kemudian, mereka mungkin membatasi ini hanya untuk literal angka; Namun, mereka memilih untuk mengizinkan juga hal-hal seperti di short x = y;mana ydidefinisikan sebagai const int y = 42;, dan kemudian mereka berakhir dengan ini.
Jeppe Stig Nielsen
88

Satu hal yang perlu diperhatikan adalah const terbatas pada tipe primitif / nilai (pengecualian adalah string)

Chris S
sumber
30
Sebenarnya constdapat digunakan untuk tipe lain juga, kecuali bahwa itu harus diinisialisasi ke nol, yang membuatnya tidak berguna :)
nawfal
6
pengecualian seperti pada System.Exception? :)
Memet Olsen
4
@nawfal Lebih tepatnya, satu-satunya jenis nilai yang constdapat digunakan, adalah sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, ditambah enumjenis. consttidak dapat digunakan untuk tipe nilai lainnya, seperti DateTimeatau TimeSpanatau BigInteger. Itu juga tidak dapat digunakan untuk IntPtrstruct (dianggap sebagai tipe "primitif" oleh sebagian orang; istilah tipe primitif membingungkan dalam C #). ↵↵ constDapat digunakan untuk semua jenis referensi . Jika jenisnya string, nilai string apa pun dapat ditentukan. Kalau tidak, nilainya harus null.
Jeppe Stig Nielsen
@JeppeStigNielsen - Saya baru-baru ini berdebat dengan servy tentang ini - dia menunjukkan bahwa Anda dapat membuat apa saja (nilai dan tipe referensi) constmenggunakan default. Untuk structtipe, ini adalah instance dengan semua anggotanya disetel ke nilai default.
Wai Ha Lee
28

Hanya Baca Statis : Nilai dapat diubah melalui statickonstruktor saat runtime. Tetapi tidak melalui Fungsi anggota.

Constant : Secara default static. Nilai tidak dapat diubah dari mana saja (Ctor, Function, runtime dll no-where)

Hanya Baca : Nilai dapat diubah melalui konstruktor saat runtime. Tetapi tidak melalui Fungsi anggota.

Anda dapat melihat pada repo saya: tipe properti C # .

Yeasin Abedin Siam
sumber
1
Berita buruk ... tautan rusak!
Fer R
2
@Fer di sana Anda pergi: github.com/yeasin90/advanced-csharp/blob/master/CSharpAdvanced/…
Yeasin Abedin Siam
Cuplikan baik Siam ভাই :)
Muhammad Ashikuzzaman
25

Kata readonlykunci berbeda dari constkata kunci. Sebuah constlapangan hanya bisa diinisialisasi pada deklarasi lapangan. Sebuah readonlylapangan dapat diinisialisasi baik di deklarasi atau dalam konstruktor. Oleh karena itu, readonlybidang dapat memiliki nilai yang berbeda tergantung pada konstruktor yang digunakan. Juga, sementara constbidang adalah konstanta waktu kompilasi, readonlybidang tersebut dapat digunakan untuk konstanta runtime

Referensi MSDN singkat dan jelas di sini

yazanpro
sumber
16

constdan readonlyserupa, tetapi mereka tidak persis sama.

Sebuah constlapangan adalah waktu kompilasi konstan, yang berarti bahwa nilai yang dapat dihitung pada saat kompilasi. Sebuah readonlylapangan memungkinkan skenario tambahan di mana beberapa kode harus dijalankan selama konstruksi dari jenis. Setelah konstruksi, readonlybidang tidak dapat diubah.

Misalnya, constanggota dapat digunakan untuk mendefinisikan anggota seperti:

struct Test
{
    public const double Pi = 3.14;
    public const int Zero = 0;
}

Karena nilai-nilai seperti 3.14 dan 0 adalah konstanta kompilasi-waktu. Namun, pertimbangkan kasus di mana Anda mendefinisikan suatu tipe dan ingin memberikan beberapa contoh pre-fab. Misalnya, Anda mungkin ingin mendefinisikan kelas Warna dan memberikan "konstanta" untuk warna umum seperti Hitam, Putih, dll. Tidak mungkin melakukan ini dengan anggota const, karena sisi kanan bukan konstanta waktu kompilasi. Orang dapat melakukan ini dengan anggota statis biasa:

public class Color
{
    public static Color Black = new Color(0, 0, 0);
    public static Color White = new Color(255, 255, 255);
    public static Color Red   = new Color(255, 0, 0);
    public static Color Green = new Color(0, 255, 0);
    public static Color Blue  = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}

Tapi kemudian tidak ada yang bisa mencegah klien Color dari mucking dengan itu, mungkin dengan menukar nilai Hitam dan Putih. Tak perlu dikatakan, ini akan menimbulkan kekhawatiran bagi klien lain dari kelas Warna. Fitur "readonly" membahas skenario ini.

Dengan hanya memasukkan readonlykata kunci dalam deklarasi, kami menjaga inisialisasi yang fleksibel sambil mencegah kode klien dari mucking sekitar.

public class Color
{
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red   = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue  = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}

Sangat menarik untuk dicatat bahwa anggota const selalu statis, sedangkan anggota readonly bisa statis atau tidak, seperti bidang biasa.

Dimungkinkan untuk menggunakan kata kunci tunggal untuk kedua tujuan ini, tetapi ini mengarah ke masalah versi atau masalah kinerja. Asumsikan sejenak bahwa kami menggunakan satu kata kunci untuk ini (const) dan pengembang menulis:

public class A
{
    public static const C = 0;
}

dan pengembang lain menulis kode yang mengandalkan A:

public class B
{
    static void Main() => Console.WriteLine(A.C);
}

Sekarang, dapatkah kode yang dihasilkan mengandalkan fakta bahwa AC adalah konstanta waktu kompilasi? Yaitu, bisakah penggunaan AC diganti dengan nilai 0? Jika Anda mengatakan "ya" untuk ini, maka itu berarti bahwa pengembang A tidak dapat mengubah cara AC diinisialisasi - ini mengikat tangan pengembang A tanpa izin.

Jika Anda mengatakan "tidak" untuk pertanyaan ini, maka optimasi penting tidak terjawab. Mungkin penulis A yakin bahwa AC akan selalu nol. Penggunaan const dan readonly memungkinkan pengembang A untuk menentukan maksud. Ini membuat perilaku versi yang lebih baik dan juga kinerja yang lebih baik.

Ramesh Rajendran
sumber
12

Preferensi saya adalah menggunakan const kapan saja saya bisa, yang seperti yang disebutkan di atas terbatas pada ekspresi literal atau sesuatu yang tidak memerlukan evaluasi.

Jika saya menghadapi batasan itu, maka saya mundur ke statis baca saja , dengan satu peringatan. Saya biasanya akan menggunakan properti statis publik dengan pengambil dan bidang baca statis pribadi pendukung seperti yang disebutkan Marc di sini .

Peter Meyer
sumber
7

Const: Const tidak lain adalah "konstan", variabel yang nilainya konstan tetapi pada waktu kompilasi. Dan itu wajib untuk memberikan nilai padanya. Secara default, const adalah statis dan kami tidak dapat mengubah nilai variabel const di seluruh program.

ReadOnly Statis: Nilai variabel tipe Readonly Statis dapat diberikan pada saat runtime atau ditugaskan pada waktu kompilasi dan diubah pada saat runtime. Tetapi nilai variabel ini hanya dapat diubah dalam konstruktor statis. Dan tidak bisa diubah lebih lanjut. Itu dapat berubah hanya sekali saat runtime

Referensi: c-sharpcorner

mayank
sumber
6

Bidang baca statis hanya menguntungkan saat mengekspos ke majelis lain nilai yang mungkin berubah di versi yang lebih baru.

Misalnya, anggap majelis Xmemperlihatkan konstanta sebagai berikut:

public const decimal ProgramVersion = 2.3;

Jika rakitan Yreferensi Xdan menggunakan konstanta ini, nilai 2.3 akan dimasukkan ke rakitan Ysaat dikompilasi. Ini berarti bahwa jika Xnanti dikompilasi ulang dengan konstanta yang ditetapkan ke 2.4, Ymasih akan menggunakan nilai lama 2.3 hingga Ydikompilasi ulang. Bidang readonly statis menghindari masalah ini.

Cara lain untuk melihat ini adalah bahwa nilai apa pun yang mungkin berubah di masa depan tidak konstan menurut definisi, dan karenanya tidak boleh direpresentasikan sebagai nilai.

Yagnesh Cangi
sumber
3

const:

  1. nilai harus diberikan pada saat deklarasi
  2. kompilasi waktu konstan

hanya baca:

  1. nilai dapat diberikan pada saat deklarasi atau selama runtime menggunakan konstruktor. Nilai dapat bervariasi tergantung pada konstruktor yang digunakan.
  2. jalankan waktu konstan
dasumohan89
sumber
3

Const : nilai-nilai variabel const harus didefinisikan bersama dengan deklarasi dan setelah itu tidak akan berubah. const secara statis bersifat statis sehingga tanpa membuat instance kelas kita dapat mengaksesnya. ini memiliki nilai pada waktu kompilasi

ReadOnly : nilai readonly variabel yang dapat kita definisikan saat mendeklarasikan serta menggunakan konstruktor saat runtime. variabel readonly tidak dapat mengakses tanpa instance kelas.

Static readonly : nilai variabel readonly statis yang dapat kita definisikan saat mendeklarasikan serta hanya melalui konstruktor statis tetapi tidak dengan konstruktor lain. Variabel ini juga dapat kita akses tanpa membuat instance kelas (Sebagai variabel statis).

baca statis akan menjadi pilihan yang lebih baik jika kita harus mengkonsumsi variabel dalam majelis yang berbeda. Silakan periksa detail lengkap di tautan di bawah ini

https://www.stum.de/2009/01/14/const-strings-a-very-convenient-way-to-shoot-yself-in-the-foot/

pengguna1756922
sumber
Bisakah Anda memberi tahu saya mengapa Anda downvote jawabannya, sehingga saya dapat memperbarui diri saya dan juga di sini.
user1756922
Bukan DV, tapi mungkin saja jawaban ini tidak benar-benar menambahkan apa pun ke jawaban yang sudah komprehensif di sini.
Marc L.
memang, ingat di Jawa kembali pada akhir 90-an kami memiliki dalam proyek beberapa orang menghasilkan guci yang berbeda dengan file kelas yang interoperated (direferensikan satu sama lain) dan public const string mengalami masalah versi, karena mereka disalin sekitar
George Birbilis
2

Ada perbedaan kecil antara bidang const dan baca statis di C # .Net

const harus diinisialisasi dengan nilai pada waktu kompilasi.

const secara default statis dan perlu diinisialisasi dengan nilai konstan, yang tidak dapat dimodifikasi kemudian. Itu tidak bisa digunakan dengan semua tipe data. Untuk ex-DateTime. Itu tidak bisa digunakan dengan tipe data DateTime.

public const DateTime dt = DateTime.Today;  //throws compilation error
public const string Name = string.Empty;    //throws compilation error
public static readonly string Name = string.Empty; //No error, legal

readonly dapat dinyatakan sebagai statis, tetapi tidak perlu. Tidak perlu diinisialisasi pada saat deklarasi. Nilainya dapat ditetapkan atau diubah menggunakan konstruktor satu kali. Jadi ada kemungkinan untuk mengubah nilai bidang hanya baca sekali (tidak masalah, apakah itu statis atau tidak), yang tidak mungkin dengan const.

Chirag
sumber
0

Konstanta seperti namanya, bidang yang tidak berubah dan biasanya didefinisikan secara statis pada waktu kompilasi dalam kode.

Variabel hanya baca adalah bidang yang dapat berubah dalam kondisi tertentu.

Mereka dapat diinisialisasi ketika Anda pertama kali mendeklarasikannya seperti konstanta, tetapi biasanya mereka diinisialisasi selama konstruksi objek di dalam konstruktor.

Mereka tidak dapat diubah setelah inisialisasi terjadi, dalam kondisi yang disebutkan di atas.

Baca-saja statis terdengar seperti pilihan yang buruk bagi saya karena, jika itu statis dan tidak pernah berubah, jadi gunakan saja konstelasi publik, jika itu dapat berubah maka itu tidak konstan dan kemudian, tergantung pada kebutuhan Anda, Anda dapat menggunakan baca -only atau hanya variabel biasa.

Juga, perbedaan penting lainnya adalah konstanta milik kelas, sedangkan variabel read-only milik instance!

Claudiu Cojocaru
sumber
0

Sebuah konst (ditentukan pada waktu kompilasi) dapat digunakan dalam kasus-kasus di mana statik yang tidak dapat dibaca, seperti dalam pernyataan switch, atau konstruktor atribut. Ini karena bidang hanya baca diselesaikan pada waktu berjalan, dan beberapa konstruksi kode memerlukan jaminan waktu kompilasi. Statis yang dapat dibaca dapat dihitung dalam konstruktor, yang seringkali merupakan hal yang penting dan berguna. Perbedaannya fungsional, sebagaimana seharusnya penggunaannya menurut saya.

Dalam hal alokasi memori, setidaknya dengan string (menjadi tipe referensi), tampaknya tidak ada perbedaan dalam bahwa keduanya diinternir dan akan merujuk pada satu contoh yang diinternir.

Secara pribadi, default saya hanya statis, karena lebih masuk akal semantik dan logis bagi saya, terutama karena sebagian besar nilai tidak diperlukan pada waktu kompilasi. Dan, omong-omong, statika yang bisa dibaca publik bukan tidak biasa atau tidak umum sama sekali seperti yang dinyatakan oleh jawaban: misalnya, System.String.Emptyadalah satu.

DvS
sumber
0

Perbedaan lain antara mendeklarasikan const dan static readonly adalah dalam alokasi memori.

Bidang statis milik jenis objek daripada turunan dari jenis itu. Akibatnya, setelah kelas direferensikan untuk pertama kalinya, bidang statis akan "hidup" di memori untuk sisa waktu, dan contoh yang sama dari bidang statis akan dirujuk oleh semua contoh dari tipe tersebut.

Di sisi lain, bidang const "milik turunan dari tipe.

Jika ingatan akan alokasi lebih penting bagi Anda, lebih baik gunakan const . Jika kecepatan, maka gunakan baca statis saja .

Boris Lipschitz
sumber