Eine freundschaftliche Debatte mit einem Kollegen darüber führen. Wir haben einige Gedanken darüber, aber fragen uns, was die SO-Menge darüber denkt?
Eine freundschaftliche Debatte mit einem Kollegen darüber führen. Wir haben einige Gedanken darüber, aber fragen uns, was die SO-Menge darüber denkt?
Antworten:
Ein Grund ist, dass es keine CLR-Unterstützung für einen schreibgeschützten lokalen gibt. Readonly wird zunächst in den CLR / CLI-Opcode übersetzt. Dieses Flag kann nur auf Felder angewendet werden und hat keine Bedeutung für ein lokales. In der Tat wird die Anwendung auf einen lokalen Code wahrscheinlich zu nicht überprüfbarem Code führen.
Dies bedeutet nicht, dass C # dies nicht tun konnte. Aber es würde dem gleichen Sprachkonstrukt zwei verschiedene Bedeutungen geben. Die Version für Einheimische hätte keine CLR-äquivalente Zuordnung.
readonly
Schlüsselwort für Felder muss von der CLI unterstützt werden, da seine Auswirkung für andere Assemblys sichtbar ist . Es würde lediglich bedeuten, dass die Variable zur Kompilierungszeit nur eine Zuordnung in der Methode hat.
const
(was in C ++ eher C # readonly
als C # ähnelt const
, obwohl es beide Rollen spielen kann). C ++ unterstützt jedoch const
lokale automatische Variablen. Daher ist das Fehlen einer CLR-Unterstützung für ein C # readonly
für eine lokale Variable irrelevant.
using
und out
genau das tun und die Welt nicht zusammenbricht.
Ich denke, es ist ein schlechtes Urteil von Seiten der C # -Architekten. Der schreibgeschützte Modifikator für lokale Variablen hilft bei der Aufrechterhaltung der Programmkorrektheit (genau wie bei Asserts) und kann dem Compiler möglicherweise dabei helfen, den Code zu optimieren (zumindest bei anderen Sprachen). Die Tatsache, dass es derzeit in C # nicht zulässig ist, ist ein weiteres Argument dafür, dass einige der "Merkmale" von C # lediglich eine Durchsetzung des persönlichen Codierungsstils seiner Ersteller sind.
Bei der Beantwortung von Jareds Antwort müsste es sich wahrscheinlich nur um eine Funktion zur Kompilierungszeit handeln. Der Compiler würde Ihnen verbieten, nach der ersten Deklaration (die eine Zuweisung enthalten müsste) in die Variable zu schreiben.
Kann ich darin Wert sehen? Potenziell - aber nicht viel, um ehrlich zu sein. Wenn Sie nicht leicht erkennen können, ob eine Variable an anderer Stelle in der Methode zugewiesen wird oder nicht, ist Ihre Methode zu lang.
Für was es wert ist , hat Java diese Funktion (mit dem final
Modifikator) , und ich habe sehr selten es als in den Fällen verwendet , um andere zu sehen , wo es hat verwendet werden , um die Variable zu ermöglichen , von einer anonymen inneren Klasse erfaßt werden - und wo es ist verwendet, gibt es mir eher einen Eindruck von Unordnung als nützliche Informationen.
readonly
/ final
Werte von Variablen mit ihren val
und var
Schlüsselwörtern. Im Scala-Code werden lokale val
s sehr häufig verwendet (und werden tatsächlich lokalen var
s vorgezogen ). Ich vermute, dass die Hauptgründe dafür, dass der final
Modifikator in Java nicht häufiger verwendet wird, a) Unordnung und b) Faulheit sind.
readonly
wäre dies nicht übermäßig wichtig. Andererseits readonly
würde der Compiler für lokale Variablen, die in Abschlüssen verwendet werden, in vielen Fällen effizienteren Code generieren lassen. Wenn die Ausführung in einen Block eintritt, der einen Abschluss enthält, muss der Compiler derzeit ein neues Heap-Objekt für die geschlossenen Variablen erstellen, selbst wenn kein Code ausgeführt wird, der den Abschluss verwenden würde . Wenn eine Variable schreibgeschützt wäre, könnte Code außerhalb des Abschlusses eine normale Variable verwenden. Nur wenn ein Delegat für die Schließung erstellt wird ...
Ein Vorschlag, der nur Einheimische und Parameter enthält, wurde vom C # 7-Designteam kurz besprochen. Aus C # Design Meeting Notes für den 21. Januar 2015 :
Parameter und Einheimische können von Lambdas erfasst und gleichzeitig abgerufen werden, aber es gibt keine Möglichkeit, sie vor Problemen des gemeinsamen gegenseitigen Zustands zu schützen: Sie können nicht schreibgeschützt werden.
Im Allgemeinen sollen die meisten Parameter und viele Einheimische niemals zugewiesen werden, nachdem sie ihren Anfangswert erhalten haben. Wenn sie nur zugelassen werden, würde dies ihre Absicht klar zum Ausdruck bringen.
Ein Problem ist, dass diese Funktion ein "attraktives Ärgernis" sein könnte. Während das "Richtige" fast immer darin besteht, Parameter und Einheimische schreibgeschützt zu machen, würde dies den Code erheblich überladen.
Eine Idee, um dies teilweise zu mildern, besteht darin, zuzulassen, dass die Kombination readonly var für eine lokale Variable auf val oder etwas Kurzes wie dieses kontrahiert wird. Allgemeiner könnten wir versuchen, einfach an ein kürzeres Schlüsselwort als das etablierte Readonly zu denken, um die Readonly-Ness auszudrücken.
Die Diskussion wird im C # Language Design Repo fortgesetzt. Stimmen Sie ab, um Ihre Unterstützung zu zeigen. https://github.com/dotnet/csharplang/issues/188
Es ist ein Versehen für C # -Sprachendesigner. F # hat das Schlüsselwort val und basiert auf CLR. Es gibt keinen Grund, warum C # nicht dieselbe Sprachfunktion haben kann.
Ich war dieser Mitarbeiter und es war nicht freundlich! (Ich mache nur Spaß)
Ich würde die Funktion nicht eliminieren, da es besser ist, kurze Methoden zu schreiben. Es ist ein bisschen so, als würde man sagen, man sollte keine Threads verwenden, weil sie hart sind. Gib mir das Messer und lass mich dafür verantwortlich sein, dass ich mich nicht schneide.
Persönlich wollte ich ein anderes Schlüsselwort vom Typ "var" wie "inv" (invarient) oder "rvar", um Unordnung zu vermeiden. Ich habe in letzter Zeit F # studiert und finde die unveränderliche Sache ansprechend.
Ich wusste nie, dass Java das hat.
Ich möchte lokale schreibgeschützte Variablen auf die gleiche Weise wie lokale const- Variablen. Aber es hat weniger Priorität als andere Themen.
Vielleicht ist seine Priorität der gleiche Grund für C # -Designer, diese Funktion (noch!) Nicht zu implementieren. Es sollte jedoch einfach (und abwärtskompatibel) sein, lokale schreibgeschützte Variablen in zukünftigen Versionen zu unterstützen.
Schreibgeschützt bedeutet, dass die Instanzvariable nur im Konstruktor festgelegt werden kann. Wenn eine Variable lokal deklariert wird, hat sie keine Instanz (sie befindet sich nur im Gültigkeitsbereich) und kann vom Konstruktor nicht berührt werden.
Ich weiß, das beantwortet nicht das Warum Ihrer Frage. Wie auch immer, diejenigen, die diese Frage lesen, werden den folgenden Code dennoch zu schätzen wissen.
Wenn Sie sich beim Überschreiben einer lokalen Variablen, die nur einmal festgelegt werden soll, wirklich darum kümmern, sich selbst in den Fuß zu schießen, und Sie sie nicht zu einer global zugänglichen Variablen machen möchten, können Sie so etwas tun.
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);
}
}
Anwendungsbeispiel:
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
Vielleicht nicht so wenig Code wie, rvar rInt = 5
aber es funktioniert.
Sie können schreibgeschützte lokale Variablen in C # deklarieren, wenn Sie den interaktiven C # -Compiler verwenden 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)
Sie können auch schreibgeschützte lokale Variablen im Skriptformat deklarieren .csx
.
message
handelt es sich hier nicht um eine Variable, sondern um ein Feld. Dies ist kein Nitpicking, da die Unterscheidung auch in interaktivem C # eindeutig vorhanden int x; Console.WriteLine(x)
ist : ist legal interaktives C # (weil x
es ein Feld ist und implizit initialisiert wird), aber void foo() { int x; Console.WriteLine(x); }
nicht (weil x
es eine Variable ist und verwendet wird, bevor es zugewiesen wird). Außerdem Expression<Func<int>> y = x; ((MemberExpression) y.Body).Member.MemberType
wird sich herausstellen, dass x
es sich wirklich um ein Feld und nicht um eine lokale Variable handelt.
c # hat bereits eine schreibgeschützte Variable, wenn auch in einer etwas anderen Syntax:
Betrachten Sie die folgenden Zeilen:
var mutable = myImmutableCalculationMethod();
readonly var immutable = mutable; // not allowed in C# 8 and prior versions
return immutable;
Vergleichen mit:
var mutable = myImmutableCalculationMethod();
string immutable() => mutable; // allowed in C# 7
return immutable();
Zugegeben, die erste Lösung könnte möglicherweise weniger zu schreibender Code sein. Das zweite Snippet macht das Readonly jedoch explizit, wenn auf die Variable verwiesen wird.
readonly var im = new List<string>(); im.Add("read-only variable, mutable object!");
.
verwenden const
Schlüsselwort, um eine schreibgeschützte Variable zu erstellen.
Referenz: 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
bei dem die Variable möglicherweise nur während der Initialisierung zugewiesen wird, nicht für den csharp-Stil, const
bei dem nur Ausdrücke zur Kompilierungszeit verwendet werden dürfen. ZB können Sie nicht tun, const object c = new object();
aber ein readonly
Einheimischer würde Ihnen erlauben, dies zu tun.