Avoir un débat amical avec un collègue à ce sujet. Nous avons quelques réflexions à ce sujet, mais nous nous demandons ce que la foule SO en pense?
Avoir un débat amical avec un collègue à ce sujet. Nous avons quelques réflexions à ce sujet, mais nous nous demandons ce que la foule SO en pense?
Réponses:
L'une des raisons est qu'il n'y a pas de support CLR pour un local en lecture seule. Readonly est traduit dans l'opcode initonly CLR / CLI. Cet indicateur ne peut être appliqué qu'aux champs et n'a aucune signification pour un local. En fait, l'appliquer à un local produira probablement un code invérifiable.
Cela ne signifie pas que C # ne peut pas faire cela. Mais cela donnerait deux significations différentes à la même construction de langage. La version pour les locaux n'aurait pas de mappage équivalent CLR.
readonly
mot-clé pour les champs doit être pris en charge par l'interface de ligne de commande car son effet est visible par les autres assemblys. Tout cela signifierait que la variable n'a qu'une seule affectation dans la méthode au moment de la compilation.
const
(qui en C ++ ressemble plus à C # readonly
qu'à C # const
, bien qu'il puisse jouer les deux rôles). Pourtant, C ++ prend en charge const
la variable automatique locale. Par conséquent, le manque de support CLR pour un C # readonly
pour une variable locale n'est pas pertinent.
using
et out
font exactement cela et le monde ne s'est pas effondré.
Je pense que c'est un mauvais jugement de la part des architectes C #. Le modificateur readonly sur les variables locales aide à maintenir l'exactitude du programme (tout comme les assertions) et peut potentiellement aider le compilateur à optimiser le code (au moins dans le cas d'autres langages). Le fait qu'il soit interdit en C # pour le moment, est un autre argument selon lequel certaines des "fonctionnalités" de C # sont simplement une application du style de codage personnel de ses créateurs.
Pour répondre à la réponse de Jared, il faudrait probablement juste une fonctionnalité de compilation - le compilateur vous interdirait d'écrire dans la variable après la déclaration initiale (qui devrait inclure une affectation).
Puis-je voir la valeur à cela? Potentiellement - mais pas beaucoup, pour être honnête. Si vous ne pouvez pas facilement dire si une variable va être affectée ailleurs dans la méthode, alors votre méthode est trop longue.
Pour ce que ça vaut, Java a cette fonctionnalité (en utilisant le final
modificateur) et je l'ai très rarement vue utilisée sauf dans les cas où elle doit être utilisée pour permettre à la variable d'être capturée par une classe interne anonyme - et où elle se trouve utilisé, cela me donne une impression de fouillis plutôt que d'informations utiles.
readonly
/ final
des variables avec ses mots val
- var
clés et . Dans le code Scala, les locaux val
sont très fréquemment utilisés (et sont, en fait, préférés aux locaux var
). Je soupçonne que les principales raisons pour lesquelles le final
modificateur n'est pas utilisé plus fréquemment en Java sont a) l'encombrement et b) la paresse.
readonly
ce ne serait pas trop important. D'un autre côté, pour les variables locales qui sont utilisées dans les fermetures, readonly
laisserait dans de nombreux cas le compilateur générer du code plus efficace. Actuellement, quand l'exécution entre dans un bloc qui contient une fermeture, le compilateur doit créer un nouvel objet de tas pour les variables fermées, même si aucun code qui utiliserait la fermeture n'est jamais exécuté . Si une variable était en lecture seule, le code en dehors de la fermeture pourrait utiliser une variable normale; seulement quand un délégué est créé pour la fermeture ...
Une proposition en lecture seule pour les sections locales et les paramètres a été brièvement discutée par l'équipe de conception C # 7. À partir des notes de la réunion C # Design du 21 janvier 2015 :
Les paramètres et les locaux peuvent être capturés par des lambdas et ainsi accédés simultanément, mais il n'y a aucun moyen de les protéger des problèmes d'état partagé-mutuel: ils ne peuvent pas être en lecture seule.
En général, la plupart des paramètres et de nombreux paramètres locaux ne sont jamais destinés à être affectés après avoir obtenu leur valeur initiale. Autoriser la lecture seule sur eux exprimerait clairement cette intention.
Un problème est que cette fonctionnalité peut être une «nuisance intéressante». Alors que la «bonne chose» à faire serait presque toujours de rendre les paramètres et les sections locales en lecture seule, cela encombrerait considérablement le code pour le faire.
Une idée pour atténuer partiellement cela est de permettre à la combinaison de var en lecture seule sur une variable locale d'être contractée en val ou quelque chose de court comme ça. Plus généralement, nous pourrions essayer de penser simplement à un mot-clé plus court que le readonly établi pour exprimer le readonly-ness.
La discussion se poursuit dans le référentiel C # Language Design. Votez pour montrer votre soutien. https://github.com/dotnet/csharplang/issues/188
C'est un oubli pour le concepteur de langage c #. F # a le mot clé val et il est basé sur CLR. Il n'y a aucune raison pour laquelle C # ne peut pas avoir la même fonctionnalité de langage.
J'étais ce collègue et ce n'était pas sympathique! (je rigole)
Je n'éliminerais pas la fonctionnalité car il vaut mieux écrire des méthodes courtes. C'est un peu comme dire que vous ne devriez pas utiliser de threads parce qu'ils sont durs. Donnez-moi le couteau et laissez-moi être responsable de ne pas me couper.
Personnellement, je voulais un autre mot-clé de type "var" comme "inv" (invarient) ou "rvar" pour éviter l'encombrement. J'ai récemment étudié F # et je trouve la chose immuable attrayante.
Je n'ai jamais su que Java avait ça.
Je voudrais des variables locales en lecture seule de la même manière que j'aime les variables const locales . Mais il a moins de priorité que d'autres sujets.
Peut-être que sa priorité est la même raison pour les concepteurs C # de ne pas (encore!) Implémenter cette fonctionnalité. Mais il devrait être facile (et rétrocompatible) de prendre en charge les variables locales en lecture seule dans les versions futures.
Readonly signifie que le seul endroit où la variable d'instance peut être définie est dans le constructeur. Lors de la déclaration d'une variable localement, elle n'a pas d'instance (elle est juste dans la portée), et elle ne peut pas être touchée par le constructeur.
Je sais, cela ne répond pas au pourquoi de votre question. Quoi qu'il en soit, ceux qui liront cette question apprécieront peut-être le code ci-dessous.
Si vous êtes vraiment préoccupé par le fait de vous tirer une balle dans le pied lors de la substitution d'une variable locale qui ne devrait être définie qu'une seule fois, et que vous ne voulez pas en faire une variable plus accessible globalement, vous pouvez faire quelque chose comme ça.
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);
}
}
Exemple d'utilisation:
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
Peut-être pas moins de code rvar rInt = 5
mais ça marche.
Vous pouvez déclarer des variables locales en lecture seule en C #, si vous utilisez le compilateur interactif 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)
Vous pouvez également déclarer des variables locales en lecture seule au .csx
format script.
message
n'est pas une variable ici, il est compilé dans un champ. Ce n'est pas compliqué car la distinction existe également clairement dans le C # interactif: int x; Console.WriteLine(x)
est du C # interactif légal (parce que x
c'est un champ et implicitement initialisé) mais void foo() { int x; Console.WriteLine(x); }
ne l'est pas (parce que x
c'est une variable et utilisée avant d'être assignée). En outre, Expression<Func<int>> y = x; ((MemberExpression) y.Body).Member.MemberType
révélera que x
c'est vraiment un champ et non une variable locale.
c # a déjà une variable en lecture seule, bien que dans une syntaxe quelque peu différente:
Considérez les lignes suivantes:
var mutable = myImmutableCalculationMethod();
readonly var immutable = mutable; // not allowed in C# 8 and prior versions
return immutable;
Comparer avec:
var mutable = myImmutableCalculationMethod();
string immutable() => mutable; // allowed in C# 7
return immutable();
Certes, la première solution pourrait éventuellement être moins de code à écrire. Mais le 2ème extrait rendra la lecture seule explicite, lors du référencement de la variable.
readonly var im = new List<string>(); im.Add("read-only variable, mutable object!");
.
utilisez le const
mot-clé pour créer une variable en lecture seule.
référence: 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
où la variable ne peut être affectée que lors de son initialisation - pas par le style csharp const
où seules les expressions au moment de la compilation peuvent être utilisées. Par exemple, vous ne pouvez pas faire const object c = new object();
mais un readonly
local vous le permettrait.