Mengapa bukan String. Menghasilkan konstanta?

189

Di. Net mengapa String.Empty hanya membaca bukan konstanta? Saya hanya ingin tahu apakah ada yang tahu alasan di balik keputusan itu.

travis
sumber
5
Pertanyaan ini dapat menyelesaikan yang satu ini, jawabannya singkat, tidak ada yang tahu ...
gdoron mendukung Monica
Ya, +1 untuk respons Eric Lippert, terima kasih!
travis
Khususnya mengingat bahwa Decimal.Zero adalah const (dari perspektif pengguna yang ...)
Hamish Grubijan

Jawaban:

149

Alasan yang static readonlydigunakan alih-alih constadalah karena digunakan dengan kode yang tidak dikelola, seperti yang ditunjukkan oleh Microsoft di sini dalam Siaran Bersama Common Language Infrastructure 2.0 Release . File yang akan dilihat adalah sscli20\clr\src\bcl\system\string.cs.

Konstanta kosong memegang nilai string kosong. Kita perlu memanggil konstruktor String agar kompiler tidak menandainya sebagai literal.

Menandai ini sebagai literal berarti itu tidak muncul sebagai bidang yang bisa kita akses dari asli.

Saya menemukan informasi ini dari artikel praktis ini di CodeProject .

Jeff Yates
sumber
Saya akan sangat menghargai jika Anda dapat menjelaskan komentar ini (karena Jon Skeet tidak dapat ...) lihat di sini: stackoverflow.com/questions/8462697/...
gdoron mendukung Monica
2
@ gdoron: Tebakan saya (dan ini tebakan) adalah ini. Ketika suatu nilai didefinisikan sebagai literal (sebuah konstanta) nilainya dimasukkan di tempat-tempat di mana ia direferensikan sedangkan ketika itu tidak didefinisikan sebagai literal, sumber nilai direferensikan dan nilai aktual diambil pada saat runtime. Saya menduga bahwa yang terakhir dapat memastikan bahwa marshalling yang tepat dari string terjadi antara asli dan .NET saat runtime - jika itu adalah literal, mungkin kompiler asli perlu entah bagaimana menarik nilai literal ke dalam kode aslinya, yang mungkin tidak layak. Ini semua dugaan di pihak saya.
Jeff Yates
7
Itu berarti bahwa seseorang harus menggunakan "", bukan string. Terima untuk nilai parameter default dalam metode. Yang sedikit mengganggu.
nicodemus13
17
"" bisa terlihat seperti kesalahan, sementara string. Keluasan menunjukkan niat yang disengaja
Christopher Stevenson
3
@ Jeffeates Saya menambahkan bahwa fakta bahwa itu tidak konsisten sudah menjengkelkan. Orang akan melihat sisa kode dan bertanya-tanya "mengapa dia menggunakan" "di sini, bukan String.Empty?". Saya serius mempertimbangkan tidak menggunakan String.Emptylagi karena alasan itu saja.
julealgon
24

Saya pikir ada banyak kebingungan dan tanggapan buruk di sini.

Pertama-tama, constbidang adalah staticanggota ( bukan anggota contoh ).

Periksa bagian 10.4 Konstanta dari spesifikasi bahasa C #.

Meskipun konstanta dianggap sebagai anggota statis, deklarasi konstan tidak memerlukan atau mengizinkan pengubah statis.

Jika public constanggota statis, orang tidak dapat mempertimbangkan bahwa konstanta akan membuat Obyek baru.

Dengan ini, baris kode berikut melakukan hal yang persis sama sehubungan dengan pembuatan Objek baru.

public static readonly string Empty = "";
public const string Empty = "";

Berikut adalah catatan dari Microsoft yang menjelaskan perbedaan antara 2:

Kata kunci readonly berbeda dari kata kunci const. Bidang const hanya dapat diinisialisasi pada deklarasi bidang. Bidang baca-saja dapat diinisialisasi baik di deklarasi atau di konstruktor. Oleh karena itu, bidang hanya baca dapat memiliki nilai yang berbeda tergantung pada konstruktor yang digunakan. Juga, sementara bidang const adalah konstanta waktu kompilasi, bidang readonly dapat digunakan untuk konstanta runtime, ...

Jadi saya menemukan bahwa satu-satunya jawaban yang masuk akal di sini adalah jawaban Jeff Yates.

bruno conde
sumber
+1 untuk kata-kata baik dan klarifikasi mengenai spesifikasi C # pada const dan hanya baca statis.
Jeff Yates
17
Membaca ulang ini, saya tidak setuju const stringdan static readonly stringmelakukan hal yang sama. Nilai-nilai konstanta digantikan dalam kode tertaut sedangkan nilai-nilai statis baca dirujuk. Jika Anda memiliki constdi perpustakaan A yang digunakan oleh perpustakaan B, perpustakaan B akan mengganti semua referensi ke constvariabel itu dengan nilai literalnya; jika variabel itu static readonlysebaliknya, itu akan dirujuk dan nilainya ditentukan saat runtime.
Jeff Yates
3
Poin Jeff penting ketika merujuk perpustakaan. Jika Anda mengkompilasi ulang A dan mendistribusikannya kembali, tanpa mengkompilasi ulang B , B masih akan menggunakan nilai-nilai lama.
Mark Sowul
5
String.Empty read only instead of a constant?

Jika Anda membuat string konstan , maka kompiler diganti dengan string sebenarnya di mana pun Anda menyebutnya dan Anda mengisi kode Anda dengan string yang sama di seluruh dan ketika kode berjalan juga perlu membaca lagi dan lagi bahwa string dari memori yang berbeda data.

Jika Anda membiarkan string hanya dibaca di satu tempat saja String.Empty, program menyimpan string yang sama hanya di satu tempat dan membacanya, atau merujuknya - menjaga data dalam memori minimum.

Juga jika Anda mengkompilasi dll menggunakan String.Empty sebagai const, dan untuk alasan apa pun String.Empty berubah, maka dll yang dikompilasi tidak akan berfungsi lagi sama, karena costmembuat kode di dalam untuk benar-benar menyimpan salinan string. pada setiap panggilan.

Lihat kode ini misalnya:

public class OneName
{
    const string cConst = "constant string";
    static string cStatic = "static string";
    readonly string cReadOnly = "read only string";

    protected void Fun()
    {
        string cAddThemAll ;

        cAddThemAll = cConst;
        cAddThemAll = cStatic ;
        cAddThemAll = cReadOnly;    
    }
}

akan datang oleh kompiler sebagai:

public class OneName
{
    // note that the const exist also here !
    private const string cConst = "constant string";
    private readonly string cReadOnly;
    private static string cStatic;

    static OneName()
    {
        cStatic = "static string";
    }

    public OneName()
    {
        this.cReadOnly = "read only string";
    }

    protected void Fun()
    {
        string cAddThemAll ;

        // look here, will replace the const string everywhere is finds it.
        cAddThemAll = "constant string";
        cAddThemAll = cStatic;
        // but the read only will only get it from "one place".
        cAddThemAll = this.cReadOnly;

    }
}

dan panggilan perakitan

        cAddThemAll = cConst;
0000003e  mov         eax,dword ptr ds:[09379C0Ch] 
00000044  mov         dword ptr [ebp-44h],eax 
        cAddThemAll = cStatic ;
00000047  mov         eax,dword ptr ds:[094E8C44h] 
0000004c  mov         dword ptr [ebp-44h],eax 
        cAddThemAll = cReadOnly;
0000004f  mov         eax,dword ptr [ebp-3Ch] 
00000052  mov         eax,dword ptr [eax+0000017Ch] 
00000058  mov         dword ptr [ebp-44h],eax 

Sunting: Kesalahan ketik yang diperbaiki

Aristos
sumber
Jadi, ini berarti bahwa string const harus selalu dipakai dengan kelas yang mengandung const itu? Sepertinya itu jauh lebih baik untuk menggunakan pembacaan statis saja.
the berserker
@theberserker juga lebih baik, tetapi Anda memiliki semua opsi untuk digunakan.
Aristos
> maka dll yang dikompilasi tidak akan berfungsi lagi sama, karena biaya membuat kode bagian dalam untuk benar-benar menyimpan salinan string pada setiap panggilan. @Aristos Itu tidak benar. Setelah kode dikompilasi, itu "salinan" dari string akan direferensikan di blok TEXT dari executable, dan semua kode hanya akan merujuk pada blok memori yang sama. Apa yang Anda kutip di langkah kedua hanyalah langkah menengah.
Peter Dolkens
@ user1533523 terima kasih atas catatannya - Saya akan melakukan tes ketika saya menemukan waktu untuk memeriksanya
Aristos
Bagaimana Anda mendapatkan kode perakitan itu? C # tidak dapat dikompilasi ke assembly!
jv110
0

Jawaban ini ada untuk tujuan historis.

Semula:

Karena Stringadalah kelas dan karenanya tidak dapat menjadi konstanta.

Diskusi Lanjutan:

Banyak dialog bermanfaat yang dibuat dalam memeriksa jawaban ini, dan bukannya menghapusnya, konten ini direproduksi secara langsung:

Dalam .NET, (tidak seperti dalam Java) string dan String persis sama. Dan ya, Anda dapat memiliki string konstanta literal dalam. NET - DrJokepu 3 Februari 2009 di 16:57

Apakah Anda mengatakan bahwa Kelas tidak dapat memiliki konstanta? - StingyJack 3 Feb 09 di 16:58

Ya, objek harus digunakan hanya baca. Hanya struct yang dapat melakukan konstanta. Saya pikir ketika Anda menggunakan stringbukannya Stringkompiler mengubah const menjadi hanya untuk Anda. Semua itu berkaitan dengan menjaga programmer C senang. - Garry Shutler 3 Feb 09 di 16:59

tvanfosson hanya menjelaskannya sedikit lebih verbose. "X tidak boleh berupa konstanta, karena yang mengandung Y adalah sebuah kelas" hanya sedikit terlalu bebas konteks;) - Leonidas 3 Februari 2009 di 17:01

string.Empty adalah properti statis yang mengembalikan instance dari kelas String, yaitu string kosong, bukan kelas string itu sendiri. - tvanfosson 3 Feb 09 di 17:01

Empty adalah instance readonly (bukan properti) dari kelas String. - senfo 3 Februari 2009 pada 17:02

Kepala sakit. Saya masih berpikir saya benar, tetapi sekarang saya kurang yakin. Diperlukan penelitian malam ini! - Garry Shutler 3 Februari 2009 pada 17:07

String kosong adalah turunan dari kelas string. Kosong adalah bidang statis (bukan properti, saya berdiri dikoreksi) pada kelas String. Pada dasarnya perbedaan antara pointer dan hal itu menunjuk. Jika tidak dibaca hanya kita bisa mengubah contoh yang bidang isian merujuk. - tvanfosson 3 Februari 2009 pada 17:07

Garry, Anda tidak perlu melakukan riset apa pun. Pikirkan tentang itu. String adalah kelas. Kosong adalah turunan dari String. - senfo 3 Februari 2009 pada 17:12

Ada sesuatu yang saya tidak mengerti: bagaimana mungkin konstruktor statis dari kelas String membuat turunan dari kelas String? Bukankah itu semacam skenario "ayam atau telur"? - DrJokepu 3 Feb 09 pada 17:12 5

Jawaban ini akan benar untuk hampir semua kelas lain selain System.String. .NET melakukan banyak kinerja casing khusus untuk string, dan salah satunya adalah bahwa Anda BISA memiliki konstanta string, coba saja. Dalam hal ini, Jeff Yates memiliki jawaban yang benar. - Joel Mueller 3 Februari 2009 pada 19:25

Seperti dijelaskan dalam §7.18, ekspresi-konstan adalah ekspresi yang dapat sepenuhnya dievaluasi pada waktu kompilasi. Karena satu-satunya cara untuk membuat nilai non-null dari tipe referensi selain string adalah dengan menerapkan operator baru, dan karena operator baru tidak diizinkan dalam ekspresi konstan, satu-satunya nilai yang mungkin untuk konstanta tipe referensi selain string adalah nol. Dua komentar sebelumnya diambil langsung dari spesifikasi bahasa C # dan menegaskan kembali apa yang disebutkan Joel Mueller. - senfo 4 Februari 2009 pada 15:05 5

Garry Shutler
sumber
Harap beri suara jawaban yang benar. Jika Anda Mendapat Definisi, Anda akan menemukannya di kelas String dan merupakan turunan dari String. Fakta bahwa ini menunjukkan huruf kecil adalah sihir kompiler.
Garry Shutler
Bukan saya yang menurunkan Anda tetapi dalam. NET, (tidak seperti di Jawa) string dan String persis sama. Dan ya, Anda dapat memiliki string konstanta literal di .NET
Tamas Czinege
10
Jawaban ini akan benar untuk hampir semua kelas lain selain System.String. .NET melakukan banyak kinerja casing khusus untuk string, dan salah satunya adalah bahwa Anda BISA memiliki konstanta string, coba saja. Dalam hal ini, Jeff Yates memiliki jawaban yang benar.
Joel Mueller
7
Saya hampir menghapus jawaban ini sebagai jawaban yang jauh lebih baik, tetapi diskusi dalam komentar ini layak untuk dijaga.
Garry Shutler
1
@ Gary, Anda beruntung saya membaca komentar terakhir Anda, kalau tidak saya juga akan downvote. Sebuah string memiliki fitur khusus dalam .NET, yang walaupun itu adalah kelas ref, ia bisa berupa konst.
Shimmy Weitzhandler