Avere un dibattito amichevole con un collega su questo. Abbiamo alcuni pensieri su questo, ma ti chiedi cosa ne pensa la folla di SO?
Avere un dibattito amichevole con un collega su questo. Abbiamo alcuni pensieri su questo, ma ti chiedi cosa ne pensa la folla di SO?
Risposte:
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.
readonly
parola 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.
const
(che in C ++ è più simile a C # readonly
che a C # const
, sebbene possa svolgere entrambi i ruoli). Tuttavia C ++ supporta const
la variabile automatica locale. Pertanto, la mancanza del supporto CLR per un C # readonly
per la variabile locale è irrilevante.
using
e lo out
stanno facendo esattamente e il mondo non è crollato.
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.
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 final
modificatore) 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.
readonly
/ final
valori dalle variabili con le sue val
e var
le parole chiave. Nel codice Scala, le val
s locali sono usate molto frequentemente (e sono, infatti, preferite rispetto alle var
s locali ). Sospetto che le ragioni principali per cui il final
modificatore non viene utilizzato più frequentemente in Java siano a) disordine eb) pigrizia.
readonly
non sarebbe eccessivamente importante. D'altra parte, per le variabili locali che vengono utilizzate nelle chiusure, readonly
in 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 ...
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
È 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.
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.
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.
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.
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 = 5
ma funziona.
È 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 .csx
formato di script.
message
qui 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.MemberType
rivelerà che x
è davvero un campo e non una variabile locale.
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.
readonly var im = new List<string>(); im.Add("read-only variable, mutable object!");
.
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);
}
}
const
cui la variabile può essere assegnata solo durante la sua inizializzazione, non allo stile csharp const
dove possono essere utilizzate solo espressioni in fase di compilazione. Ad esempio, non puoi farlo const object c = new object();
ma un readonly
locale ti permetterebbe di farlo.