Mengapa C # melarang variabel lokal baca saja?


115

Berdebat ramah dengan rekan kerja tentang hal ini. Kami memiliki beberapa pemikiran tentang ini, tetapi bertanya-tanya apa pendapat orang-orang SO tentang ini?


4
@ColonelPanic C dan C ++ memiliki variabel lokal const, yang dapat Anda inisialisasi dengan nilai yang dihitung waktu proses.
Crashworks

1
JavaScript 2015 (ES6) memiliki tipe const. Misalnya {const myList = [1,2,3]; }. Ini adalah praktik pemrograman yang sangat baik untuk menggunakan konstruksi ini. Info lebih lanjut: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
andrew.fox

1
Bagi yang tertarik, ada saran UserVoice untuk fitur ini . Saat ini hanya duduk di 87 suara, jadi jika Anda ingin melihat variabel lokal yang hanya bisa dibaca, silakan lihat!
Ian Kemp

1
Ini bukan hanya masalah bahasa. Ini adalah masalah mayoritas di komunitas C # termasuk guru C # berperingkat tertinggi, bahwa mereka tidak peduli tentang kebenaran konstanta dan apa pun yang terkait dengannya. Resistensi adalah sia-sia.
Patrick Fromberg

1
Pembaruan 2017 : Silakan pilih permintaan fitur yang sedang dibahas di repo Desain Bahasa C #! github.com/dotnet/csharplang/issues/188
Kolonel Panic

Jawaban:


15

Salah satu alasannya adalah tidak ada dukungan CLR untuk bahasa lokal yang hanya bisa dibaca. Hanya baca diterjemahkan ke dalam opcode awal CLR / CLI. Bendera ini hanya dapat diterapkan ke bidang dan tidak memiliki arti untuk lokal. Faktanya, menerapkannya ke lokal kemungkinan akan menghasilkan kode yang tidak dapat diverifikasi.

Ini tidak berarti bahwa C # tidak bisa melakukan ini. Tetapi itu akan memberikan dua arti yang berbeda pada konstruksi bahasa yang sama. Versi untuk penduduk lokal tidak akan memiliki pemetaan yang setara dengan CLR.


57
Ini sebenarnya tidak ada hubungannya dengan dukungan CLI untuk fitur tersebut, karena variabel lokal sama sekali tidak terpapar ke rakitan lain. The readonlykata kunci untuk bidang perlu didukung oleh CLI karena efeknya adalah terlihat majelis lainnya. Artinya adalah variabel hanya memiliki satu tugas dalam metode pada waktu kompilasi.
Sam Harwell

16
Saya pikir Anda baru saja mengalihkan pertanyaan mengapa CLR tidak mendukung ini daripada memberikan alasan di baliknya. Itu memungkinkan untuk const penduduk setempat, jadi akan masuk akal untuk mengharapkan penduduk setempat juga readonly.
Chad Schouggins

9
Contoh dari ini adalah variabel yang ditentukan dalam pernyataan menggunakan. Mereka lokal ... dan hanya-baca (coba tetapkan, C # akan menambahkan kesalahan).
Softlion

7
-1 Di C ++ tidak ada dukungan kode mesin untuk const(yang di C ++ lebih seperti C # readonlydaripada C # const, meskipun dapat memainkan kedua peran tersebut). Namun C ++ mendukung constvariabel otomatis lokal. Oleh karena itu, kurangnya dukungan CLR untuk C # readonlyuntuk variabel lokal, tidak relevan.
Cheers and hth. - Alf

5
1. Ini dengan mudah dapat menjadi fitur kompilator, seperti di C ++. Dukungan CLR sama sekali tidak relevan. Perakitan mesin juga tidak mendukungnya, jadi apa? 2. (akan) kemungkinan besar menghasilkan kode yang tidak dapat diverifikasi - Saya tidak mengerti caranya, tapi mungkin saya salah. 3. itu akan memberikan dua arti yang berbeda untuk konstruksi bahasa yang sama - Saya ragu ada orang yang akan melihat ini sebagai masalah, karena usingdan outmelakukan hal itu dan dunia tidak runtuh.
Lou

66

Saya pikir itu adalah penilaian yang buruk dari arsitek C #. modifier readonly pada variabel lokal membantu menjaga ketepatan program (seperti asserts) dan berpotensi membantu compiler mengoptimalkan kode (setidaknya dalam kasus bahasa lain). Fakta bahwa itu tidak diizinkan di C # sekarang, adalah argumen lain bahwa beberapa "fitur" C # hanyalah penegakan gaya pengkodean pribadi penciptanya.


11
Saya setuju pada bagian "selamatkan pemrogram dari dirinya sendiri", tetapi untuk membantu kompiler mengoptimalkan kode, saya berpendapat bahwa kompilator dapat mengetahui dengan baik apakah suatu variabel berubah selama metode ini dan mengoptimalkannya sesuai kebutuhan. bagaimanapun juga. Menempatkan bendera 'hanya baca' sebelum sesuatu yang dikenali oleh pengoptimal untuk tujuan itu tidak benar-benar menguntungkan, namun berpotensi menyesatkan.
Cornelius

1
@ Cornelius Saya setuju bahwa ada pendapat bahwa dalam beberapa kasus penyusun menggunakan diagram aliran data untuk mengetahui peluang pengoptimalan terlepas dari kata kunci / pengubah apa pun. Tetapi menyelamatkan programmer dari dirinya sendiri dari menulis kode yang salah dan sebaliknya tidak perlu kode yang tidak dioptimalkan dapat membuka peluang pengoptimalan untuk compiler.
shuva

Bukankah kompiler modern tetap melakukan Static Single Assignment? Dalam hal ini diperdebatkan sejauh menyangkut pengoptimalan (tetapi jika kompiler mendukung SSA maka itu berarti juga sepele untuk mengimplementasikan variabel lokal assign-once).
Dai

33

Mengatasi jawaban Jared, itu mungkin hanya akan menjadi fitur waktu kompilasi - kompilator akan melarang Anda menulis ke variabel setelah deklarasi awal (yang harus menyertakan tugas).

Dapatkah saya melihat nilai ini? Secara potensial - tapi tidak banyak, jujur ​​saja. Jika Anda tidak dapat dengan mudah mengetahui apakah suatu variabel akan ditempatkan di tempat lain dalam metode, maka metode Anda terlalu panjang.

Untuk apa layak ini, Java memiliki fitur ini (menggunakan finalmodifier) dan saya sudah sangat jarang melihatnya digunakan selain dalam kasus-kasus di mana ia memiliki untuk digunakan untuk memungkinkan variabel yang akan diambil oleh kelas dalam anonim - dan di mana itu adalah digunakan, ini memberi saya kesan berantakan daripada informasi yang berguna.


75
Ada perbedaan antara melihat apakah variabel dimodifikasi dalam metode Anda dengan penglihatan dan oleh kompilator . Saya tidak melihat keberatan untuk menulis metode, menyatakan niat saya untuk tidak mengubah variabel, dan meminta kompiler memberi tahu saya ketika saya tidak sengaja melakukannya (mungkin dengan kesalahan ketik sebulan kemudian)!
A.Rex

50
Di sisi lain, di F # semua variabel bersifat read-only secara default, dan Anda harus menggunakan kata kunci 'bisa berubah' jika Anda ingin mengubahnya. Karena F # adalah bahasa .NET, saya membayangkan itu melakukan pemeriksaan waktu kompilasi yang Anda gambarkan.
Joel Mueller

2
@ A.Rex: Pertanyaannya sebenarnya adalah apakah manfaat mendapatkan compiler untuk melakukan pemeriksaan itu sepadan dengan tambahan "fluff" saat membaca kode dan tidak benar-benar memedulikannya.
Jon Skeet

3
FWIW, Scala membedakan lokal readonly/ finalnilai dari variabel dengan nya valdan varkata kunci. Dalam kode Scala, lokal sangat sering valdigunakan (dan, pada kenyataannya, lebih disukai daripada lokal ). Saya menduga bahwa alasan utama pengubah tidak digunakan lebih sering di Java adalah a) kekacauan dan b) kemalasan. varfinal
Aaron Novstrup

4
Untuk variabel lokal yang tidak digunakan dalam closure, readonlytidak akan terlalu penting. Di sisi lain, untuk variabel lokal yang digunakan dalam closure, readonlydalam banyak kasus akan membiarkan kompilator menghasilkan kode yang lebih efisien. Saat ini, saat eksekusi memasuki blok yang berisi closure, compiler harus membuat objek heap baru untuk variabel closed-over, bahkan jika tidak ada kode yang akan menggunakan closure yang dieksekusi . Jika sebuah variabel hanya-baca, kode di luar closure dapat menggunakan variabel normal; hanya ketika sebuah delegasi dibuat untuk penutupan ...
supercat

30

Proposal yang hanya dibaca penduduk setempat dan parameternya dibahas secara singkat oleh tim desain C # 7. Dari Catatan Rapat Desain C # untuk 21 Jan 2015 :

Parameter dan penduduk lokal dapat ditangkap oleh lambda dan dengan demikian diakses secara bersamaan, tetapi tidak ada cara untuk melindunginya dari masalah negara bersama: keduanya tidak dapat hanya dibaca.

Secara umum, sebagian besar parameter dan banyak lokal tidak pernah dimaksudkan untuk ditetapkan setelah mereka mendapatkan nilai awalnya. Membiarkan hanya membaca pada mereka akan mengungkapkan maksud itu dengan jelas.

Satu masalah adalah bahwa fitur ini mungkin merupakan "gangguan yang menarik". Meskipun "hal yang benar" untuk dilakukan hampir selalu membuat parameter dan penduduk setempat hanya dapat dibaca, itu akan mengacaukan kode secara signifikan untuk melakukannya.

Ide untuk mengurangi sebagian hal ini adalah dengan mengizinkan kombinasi readonly var pada variabel lokal untuk dikontrakkan ke val atau sesuatu yang singkat seperti itu. Secara lebih umum, kami dapat mencoba untuk hanya memikirkan kata kunci yang lebih pendek daripada kata kunci yang sudah ada untuk mengekspresikan hanya-baca.

Diskusi berlanjut di repo Desain Bahasa C #. Pilih untuk menunjukkan dukungan Anda. https://github.com/dotnet/csharplang/issues/188


bisa juga menjadikan readonly sebagai default (melalui beberapa opsi atau kata kunci atau apapun). sebagian besar variabel dan parameter harus dapat dibaca, dengan hanya sedikit yang dapat ditulis. dan meminimalkan jumlah yang dapat ditulis biasanya merupakan hal yang baik.
Dave Cousineau

12

Ini adalah pengawasan bagi desainer bahasa c #. F # memiliki kata kunci val dan didasarkan pada CLR. Tidak ada alasan C # tidak dapat memiliki fitur bahasa yang sama.


7

Saya adalah rekan kerja itu dan itu tidak ramah! (hanya bercanda)

Saya tidak akan menghilangkan fitur tersebut karena lebih baik menulis metode singkat. Ini seperti mengatakan Anda tidak boleh menggunakan utas karena sulit. Beri aku pisau dan biarkan aku bertanggung jawab untuk tidak memotong diriku sendiri.

Secara pribadi, saya ingin kata kunci jenis "var" lain seperti "inv" (invarient) atau "rvar" untuk menghindari kekacauan. Saya telah mempelajari F # akhir-akhir ini dan menemukan hal yang kekal itu menarik.

Tidak pernah tahu Jawa punya ini.


5

Saya ingin variabel readonly lokal dengan cara yang sama seperti yang saya suka variabel const lokal . Tetapi memiliki prioritas yang kurang dari topik lainnya.
Mungkin prioritasnya adalah alasan yang sama bagi desainer C # untuk tidak (belum!) Mengimplementasikan fitur ini. Tapi itu harus mudah (dan kompatibel ke belakang) untuk mendukung variabel hanya baca lokal di versi mendatang.


2

Hanya baca berarti satu-satunya tempat variabel instance dapat disetel adalah di konstruktor. Saat mendeklarasikan variabel secara lokal, ia tidak memiliki instance (hanya dalam cakupan), dan tidak dapat disentuh oleh konstruktor.


6
Itulah arti 'readonly' saat ini di C #, tapi bukan itu pertanyaannya. 'read only' memiliki arti bahasa Inggris yang tampaknya memiliki aplikasi intuitif ke variabel lokal: Anda tidak dapat menulis padanya (setelah diinisialisasi). Itu tampak sangat mirip artinya ketika diterapkan pada variabel instan, jadi mengapa (seperti dalam justifikasi, saya pikir) tidak dapat menerapkannya ke variabel lokal?
Spike0xff

0

Saya tahu, ini tidak menjawab mengapa pertanyaan Anda. Bagaimanapun, mereka yang membaca pertanyaan ini mungkin menghargai kode di bawah ini.

Jika Anda benar-benar khawatir dengan masalah saat menimpa variabel lokal yang seharusnya hanya disetel sekali, dan Anda tidak ingin menjadikannya variabel yang lebih dapat diakses secara global, Anda dapat melakukan sesuatu seperti ini.

    public class ReadOnly<T>
    {
        public T Value { get; private set; }

        public ReadOnly(T pValue)
        {
            Value = pValue;
        }

        public static bool operator ==(ReadOnly<T> pReadOnlyT, T pT)
        {
            if (object.ReferenceEquals(pReadOnlyT, null))
            {
                return object.ReferenceEquals(pT, null);
            }
            return (pReadOnlyT.Value.Equals(pT));
        }

        public static bool operator !=(ReadOnly<T> pReadOnlyT, T pT)
        {
            return !(pReadOnlyT == pT);
        }
    }

Contoh penggunaan:

        var rInt = new ReadOnly<int>(5);
        if (rInt == 5)
        {
            //Int is 5 indeed
        }
        var copyValueOfInt = rInt.Value;
        //rInt.Value = 6; //Doesn't compile, setter is private

Mungkin tidak sesedikit kode rvar rInt = 5tetapi berhasil.


Itu tidak membantu di sini. Masalah dengan variabel 'var' ini adalah: {var five = 5 five = 6; Assert.That (lima == 5)}
Murray

0

Anda dapat mendeklarasikan variabel lokal readonly di C #, jika Anda menggunakan compiler interaktif C # csi:

>"C:\Program Files (x86)\MSBuild\14.0\Bin\csi.exe"
Microsoft (R) Visual C# Interactive Compiler version 1.3.1.60616
Copyright (C) Microsoft Corporation. All rights reserved.

Type "#help" for more information.
> readonly var message = "hello";
> message = "goodbye";
(1,1): error CS0191: A readonly field cannot be assigned to (except in a constructor or a variable initializer)

Anda juga dapat mendeklarasikan variabel lokal hanya baca dalam .csxformat skrip.


5
Per pesan kesalahan, messagebukan variabel di sini, ini dikompilasi ke bidang. Ini bukan nitpicking karena perbedaannya jelas ada dalam C # interaktif juga: int x; Console.WriteLine(x)adalah interaktif hukum C # (karena xmerupakan bidang dan diinisialisasi secara implisit) tetapi void foo() { int x; Console.WriteLine(x); }tidak (karena xmerupakan variabel dan digunakan sebelum ditetapkan). Juga, Expression<Func<int>> y = x; ((MemberExpression) y.Body).Member.MemberTypeakan mengungkapkan bahwa xitu benar-benar bidang dan bukan variabel lokal.
Jeroen Mostert

0

c # sudah memiliki var hanya-baca, meskipun dalam sintaks yang agak berbeda:

Pertimbangkan baris berikut:

var mutable = myImmutableCalculationMethod();
readonly var immutable = mutable; // not allowed in C# 8 and prior versions
return immutable;

Dibandingkan dengan:

var mutable = myImmutableCalculationMethod();
string immutable() => mutable; // allowed in C# 7
return immutable();

Memang, solusi pertama mungkin lebih sedikit kode untuk ditulis. Tapi potongan kedua akan membuat eksplisit baca, saat mereferensikan variabel.


Itu bukan "hanya baca". Itu adalah fungsi lokal yang mengembalikan variabel yang ditangkap .. begitu banyak overhead yang tidak perlu dan sintaksis jelek yang bahkan tidak membuat variabel yang mendasarinya hanya-baca, dari sudut pandang akses kode. Juga, "bisa berubah" biasanya berlaku untuk objek, bukan variabel lokal .. dipertimbangkan: readonly var im = new List<string>(); im.Add("read-only variable, mutable object!");.
pengguna2864740

-2

menggunakan const kata kunci untuk membuat variabel hanya baca.

referensi: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/const

public class SealedTest
{
    static void Main()
    {
        const int c = 707;
        Console.WriteLine("My local constant = {0}", c);
    }
}

1
Kami tertarik dengan gaya JavaScript di constmana variabel hanya dapat ditetapkan selama inisialisasi — bukan gaya csharp di constmana hanya ekspresi waktu kompilasi yang dapat digunakan. Misalnya, Anda tidak dapat melakukannya const object c = new object();tetapi orang readonlylokal akan mengizinkan Anda melakukan ini.
binki

-5

Saya pikir itu karena sebuah fungsi yang memiliki variabel hanya-baca mungkin tidak pernah dipanggil, dan mungkin ada sesuatu tentangnya yang keluar dari ruang lingkup, dan kapan Anda perlu?

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.