Perché C # non consente la sola lettura delle variabili locali?


115

Avere un dibattito amichevole con un collega su questo. Abbiamo alcuni pensieri su questo, ma ti chiedi cosa ne pensa la folla di SO?


4
@ColonelPanic C e C ++ hanno variabili locali const, che puoi inizializzare con un valore calcolato in runtime.
Crashworks

1
JavaScript 2015 (ES6) ha il tipo const. Ad esempio {const myList = [1,2,3]; }. È una buona pratica di programmazione usare questo costrutto. Maggiori informazioni: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
andrew.fox

1
Per coloro che sono interessati, c'è un suggerimento di UserVoice per questa funzione . Attualmente ha solo 87 voti, quindi se vuoi vedere variabili di sola lettura locali, per favore vai a sbatterlo!
Ian Kemp

1
Non è solo un problema linguistico. È un problema della maggioranza della comunità C #, inclusi i guru C # con il punteggio più alto, che non si preoccupino della correttezza const e di qualsiasi cosa ad essa correlata. La resistenza è inutile.
Patrick Fromberg,

1
Aggiornamento 2017 : votare per la richiesta di funzionalità in discussione nel repository C # Language Design! github.com/dotnet/csharplang/issues/188
Colonel Panic

Risposte:


15

Uno dei motivi è che non esiste il supporto CLR per un locale di sola lettura. Readonly viene tradotto nell'opcode di solo inizializzazione CLR / CLI. Questo flag può essere applicato solo ai campi e non ha alcun significato per un locale. In effetti, applicarlo a un locale probabilmente produrrà codice non verificabile.

Ciò non significa che C # non possa farlo. Ma darebbe due significati diversi allo stesso costrutto linguistico. La versione per i locali non avrebbe una mappatura equivalente a CLR.


57
In realtà non ha nulla a che fare con il supporto CLI per la funzionalità, perché le variabili locali non sono in alcun modo esposte ad altri assembly. La readonlyparola chiave per i campi deve essere supportata dalla CLI perché il suo effetto è visibile ad altri assembly. Tutto ciò che significherebbe è che la variabile ha solo un'assegnazione nel metodo in fase di compilazione.
Sam Harwell,

16
Penso che tu abbia appena spostato la domanda sul perché il CLR non lo supporta piuttosto che fornire il razionale dietro di esso. Consente la presenza di locali const, quindi sarebbe ragionevole aspettarsi anche locali di sola lettura.
Chad Schouggins

9
Un esempio di ciò sono le variabili definite in un'istruzione using. Sono locali ... e di sola lettura (prova ad assegnarli, C # aggiungerà un errore).
Softlion

7
-1 In C ++ non esiste il supporto del codice macchina const(che in C ++ è più simile a C # readonlyche a C # const, sebbene possa svolgere entrambi i ruoli). Tuttavia C ++ supporta constla variabile automatica locale. Pertanto, la mancanza del supporto CLR per un C # readonlyper la variabile locale è irrilevante.
Saluti e salute. - Alf

5
1. Questa può essere facilmente una funzionalità del compilatore, come in C ++. Il supporto CLR è completamente irrilevante. Anche l'assemblaggio della macchina non lo supporta, e allora? 2. (potrebbe) produrre codice non verificabile - non vedo come, ma forse mi sbaglio. 3. darebbe due significati diversi allo stesso costrutto linguistico - dubito che qualcuno lo vedrebbe come un problema, poiché usinge lo outstanno facendo esattamente e il mondo non è crollato.
Lou

66

Penso che sia uno scarso giudizio da parte degli architetti C #. Il modificatore di sola lettura sulle variabili locali aiuta a mantenere la correttezza del programma (proprio come asserisce) e può potenzialmente aiutare il compilatore a ottimizzare il codice (almeno nel caso di altri linguaggi). Il fatto che al momento non sia consentito in C # è un altro argomento secondo cui alcune delle "funzionalità" di C # sono semplicemente un'applicazione dello stile di codifica personale dei suoi creatori.


11
Sono d'accordo sulla parte "salva il programmatore da se stesso", ma per quanto riguarda aiutare il compilatore a ottimizzare il codice, ritengo che il compilatore possa scoprire molto bene se una variabile cambia o meno nel corso del metodo e ottimizza di conseguenza in entrambi i casi. Posizionare un flag 'readonly' prima di qualcosa che l'ottimizzatore riconosce comunque a tale scopo non è davvero vantaggioso, ma potenzialmente fuorviante.
Cornelius

1
@ Cornelius Sono d'accordo sul fatto che ci siano opinioni secondo cui in alcuni casi il compilatore utilizza il diagramma del flusso di dati per capire l'opportunità di ottimizzazione indipendentemente da qualsiasi parola chiave / modificatore. Ma salvare il programmatore da se stesso dalla scrittura di codice errato e altrimenti inutilmente non ottimizzato può aprire questa opportunità di ottimizzazione per il compilatore.
shuva

I compilatori moderni non eseguono comunque l'assegnazione singola statica? In tal caso è discutibile per quanto riguarda le ottimizzazioni (ma se un compilatore supporta SSA, significa che è anche banale implementare variabili locali assegnabili una volta).
Dai

33

Affrontando la risposta di Jared, probabilmente dovrebbe essere solo una funzionalità in fase di compilazione: il compilatore ti proibirà di scrivere sulla variabile dopo la dichiarazione iniziale (che dovrebbe includere un compito).

Posso vedere valore in questo? Potenzialmente, ma non molto, ad essere onesti. Se non riesci a stabilire facilmente se una variabile verrà assegnata o meno in un'altra parte del metodo, il tuo metodo è troppo lungo.

Per quello che vale, Java ha questa caratteristica (usando il finalmodificatore) e l'ho visto molto raramente usato tranne nei casi in cui deve essere usato per consentire alla variabile di essere catturata da una classe interna anonima - e dove si trova usato, mi dà un'impressione di disordine piuttosto che informazioni utili.


75
C'è una differenza tra vedere se una variabile viene modificata o meno nel tuo metodo di vista e dal compilatore . Non vedo obiezioni a scrivere un metodo, dichiarando la mia intenzione di non modificare una variabile e facendomi avvisare dal compilatore quando lo faccio accidentalmente (forse con un errore di battitura un mese dopo)!
A. Rex

50
D'altra parte, in F # tutte le variabili sono di sola lettura per impostazione predefinita e devi usare la parola chiave 'mutabile' se vuoi essere in grado di cambiarle. Poiché F # è un linguaggio .NET, immagino che esegua il controllo in fase di compilazione che descrivi.
Joel Mueller

2
@ A.Rex: La domanda è davvero se il vantaggio di fare in modo che il compilatore esegua quel controllo vale la "confusione" extra quando si legge il codice e non se ne preoccupa.
Jon Skeet

3
FWIW, Scala distingue locali readonly/ finalvalori dalle variabili con le sue vale varle parole chiave. Nel codice Scala, le vals locali sono usate molto frequentemente (e sono, infatti, preferite rispetto alle vars locali ). Sospetto che le ragioni principali per cui il finalmodificatore non viene utilizzato più frequentemente in Java siano a) disordine eb) pigrizia.
Aaron Novstrup

4
Per le variabili locali che non vengono utilizzate nelle chiusure, readonlynon sarebbe eccessivamente importante. D'altra parte, per le variabili locali che vengono utilizzate nelle chiusure, readonlyin molti casi consentirebbe al compilatore di generare codice più efficiente. Attualmente, quando l'esecuzione entra in un blocco che contiene una chiusura, il compilatore deve creare un nuovo oggetto heap per le variabili closed-over, anche se non viene mai eseguito alcun codice che userebbe la chiusura . Se una variabile fosse di sola lettura, il codice al di fuori della chiusura potrebbe utilizzare una variabile normale; solo quando si crea un delegato per la chiusura ...
supercat

30

Una proposta di sola lettura locale e parametri per è stata brevemente discussa dal team di progettazione di C # 7. Dalle note della riunione di progettazione C # del 21 gennaio 2015 :

I parametri e le variabili locali possono essere acquisiti da lambda e quindi accessibili contemporaneamente, ma non è possibile proteggerli da problemi di stato reciproco condiviso: non possono essere di sola lettura.

In generale, la maggior parte dei parametri e molte variabili locali non devono mai essere assegnate dopo aver ottenuto il valore iniziale. Consentire la sola lettura su di essi esprimerebbe chiaramente tale intento.

Un problema è che questa caratteristica potrebbe essere un "fastidio allettante". Considerando che la "cosa giusta" da fare sarebbe quasi sempre rendere i parametri e le variabili locali in sola lettura, fare ciò ingombrerebbe notevolmente il codice.

Un'idea per alleviare in parte questo è quella di consentire alla combinazione readonly var su una variabile locale di essere contratta a val o qualcosa di breve come quello. Più in generale potremmo provare a pensare semplicemente a una parola chiave più breve di quella stabilita di sola lettura per esprimere la sola lettura.

La discussione continua nel repository C # Language Design. Vota per mostrare il tuo sostegno. https://github.com/dotnet/csharplang/issues/188


potrebbe anche rendere readonly il valore predefinito (tramite qualche opzione o parola chiave o qualsiasi altra cosa). la maggior parte delle variabili e dei parametri dovrebbero essere di sola lettura, con solo alcune scrivibili. e ridurre al minimo il numero che è possibile scrivere è generalmente una buona cosa.
Dave Cousineau

12

È una svista per il progettista del linguaggio c #. F # ha la parola chiave val ed è basato su CLR. Non c'è motivo per cui C # non possa avere la stessa funzionalità del linguaggio.


7

Ero quel collega e non era amichevole! (stavo solo scherzando)

Non eliminerei la funzionalità perché è meglio scrivere metodi brevi. È un po 'come dire che non dovresti usare i thread perché sono difficili. Dammi il coltello e lascia che sia responsabile di non tagliarmi.

Personalmente, volevo un'altra parola chiave di tipo "var" come "inv" (invarient) o "rvar" per evitare confusione. Ho studiato F # negli ultimi tempi e trovo attraente la cosa immutabile.

Non avrei mai saputo che Java avesse questo.


5

Vorrei variabili locali di sola lettura nello stesso modo in cui mi piacciono le variabili const locali . Ma ha meno priorità rispetto ad altri argomenti.
Forse la sua priorità è lo stesso motivo per cui i progettisti C # non implementano (ancora!) Questa funzionalità. Ma dovrebbe essere facile (e compatibile con le versioni precedenti) supportare le variabili di sola lettura locali nelle versioni future.


2

Sola lettura significa che l'unico posto in cui la variabile di istanza può essere impostata è nel costruttore. Quando si dichiara una variabile localmente, non ha un'istanza (è solo nell'ambito) e non può essere toccata dal costruttore.


6
Questo è il significato corrente di "readonly" in C #, ma non è questo il problema. "read only" ha un significato inglese che sembra avere un'applicazione intuitiva per una variabile locale: non puoi scrivere (dopo che è stata inizializzata). Questo sembra molto simile al significato applicato alle variabili di istanza, quindi perché (come nella giustificazione, credo) non possiamo applicarlo alle variabili locali?
Spike0xff

0

Lo so, questo non risponde al perché alla tua domanda. Ad ogni modo, coloro che leggono questa domanda potrebbero comunque apprezzare il codice qui sotto.

Se sei veramente interessato a spararti ai piedi quando sovrascrivi una variabile locale che dovrebbe essere impostata solo una volta, e non vuoi renderla una variabile più accessibile a livello globale, potresti fare qualcosa del genere.

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

Utilizzo di esempio:

        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

Forse non meno codice come rvar rInt = 5ma funziona.


Questo non aiuta qui. Questo problema con la variabile "var" è: {var five = 5 five = 6; Assert.That (five == 5)}
Murray

0

È possibile dichiarare variabili locali di sola lettura in C #, se si utilizza il compilatore interattivo 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)

È inoltre possibile dichiarare variabili locali di sola lettura nel .csxformato di script.


5
Secondo il messaggio di errore, messagequi non è una variabile, è compilata in un campo. Questo non è il pignolo perché la distinzione esiste chiaramente anche in C # interattivo: int x; Console.WriteLine(x)è legale interattivo C # (perché xè un campo e implicitamente inizializzato) ma void foo() { int x; Console.WriteLine(x); }non lo è (perché xè una variabile e usata prima che venga assegnata). Inoltre, Expression<Func<int>> y = x; ((MemberExpression) y.Body).Member.MemberTyperivelerà che xè davvero un campo e non una variabile locale.
Jeroen Mostert

0

c # ha già una variabile di sola lettura, anche se con una sintassi leggermente diversa:

Considera le seguenti righe:

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

Confrontare con:

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

Certo, la prima soluzione potrebbe essere meno codice da scrivere. Ma il secondo frammento renderà esplicito il readonly, quando si fa riferimento alla variabile.


Non è "sola lettura". Questa è una funzione locale che restituisce una variabile catturata .. quindi un sacco di overhead inutile e sintassi brutta che non rende nemmeno la variabile sottostante di sola lettura, dal punto di vista dell'accesso al codice. Inoltre, "mutabile" di solito vale per gli oggetti, le variabili non locali .. considerano: readonly var im = new List<string>(); im.Add("read-only variable, mutable object!");.
user2864740

-2

uso const parola chiave per rendere variabile di sola lettura.

riferimento: 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
Siamo interessati allo stile JavaScript in constcui la variabile può essere assegnata solo durante la sua inizializzazione, non allo stile csharp constdove possono essere utilizzate solo espressioni in fase di compilazione. Ad esempio, non puoi farlo const object c = new object();ma un readonlylocale ti permetterebbe di farlo.
binki

-5

Penso che ciò sia dovuto al fatto che una funzione che ha una variabile di sola lettura potrebbe non essere mai chiamata, e probabilmente c'è qualcosa che esce dall'ambito, e quando ne avresti bisogno?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.