web-dev-qa-db-fra.com

Pourquoi C # interdit-il les variables locales en lecture seule?

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?)

106
Brian Genisio

L'une des raisons est qu'il n'y a pas de prise en charge CLR pour un local en lecture seule. Readonly est traduit en 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 pourrait 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.

14
JaredPar

Je pense que c'est un mauvais jugement de la part des architectes C #. Le modificateur en lecture seule 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 langues). Le fait qu'il ne soit pas autorisé en C # en ce 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.

58
andriej

Pour répondre à la réponse de Jared, il faudrait probablement que ce soit une fonctionnalité au moment de la compilation - le compilateur vous interdirait d'écrire dans la variable après la déclaration initiale (qui devrait inclure une affectation).

Puis-je y voir de la valeur? 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, votre méthode est trop longue.

Pour ce que ça vaut, Java a cette fonctionnalité (en utilisant le modificateur final)) et j'ai très rarement vu l'utiliser autre que dans les cas où il a à utiliser pour permettre à la variable d'être capturée par une classe interne anonyme - et là où il est utilisé, cela me donne une impression d'encombrement plutôt que d'informations utiles.

34
Jon Skeet

Une proposition paramètres locaux et paramètres en lecture seule pour a été brièvement discutée par l'équipe de conception C # 7. De Notes de réunion de conception C # du 21 janvier 2015 :

Les paramètres et les sections locales peuvent être capturés par des lambdas et ainsi accessibles simultanément, mais il n'y a aucun moyen de les protéger contre les problèmes d'état mutuel partagé: ils ne peuvent pas être en lecture seule.

En général, la plupart des paramètres et de nombreuses sections locales ne sont jamais destinés à être attribués après avoir obtenu leur valeur initiale. Les autoriser en lecture seule exprimerait clairement cette intention.

Un problème est que cette caractéristique pourrait être une "nuisance attrayante". 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 ce faire.

Une idée pour atténuer partiellement cela est de permettre à la combinaison 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 la readonly-ness.

La discussion se poursuit dans le référentiel de conception de langage C #. Votez pour montrer votre soutien. https://github.com/dotnet/csharplang/issues/188

23
Colonel Panic

J'étais ce collègue et ce n'était pas sympa! (je rigole)

Je n'éliminerais pas la fonctionnalité car il vaut mieux écrire des méthodes courtes. C'est un peu comme dire de ne pas utiliser de threads car ils sont durs. Donnez-moi le couteau et laissez-moi la responsabilité 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 étudié F # récemment et je trouve la chose immuable attrayante.

Je ne savais pas Java avait cela.

7
Mike

Je voudrais des variables locales en lecture seule de la même manière que j'aime des variables locales const variables. Mais il a moins de priorité que d'autres sujets.
Peut-être que son 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 futures versions.

5
brgerner

C'est une erreur pour le concepteur de langage c #. F # a un mot-clé val et il est basé sur CLR. Il n'y a aucune raison que C # ne puisse pas avoir la même fonctionnalité de langue.

5
Derek Liang

En lecture seule 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 de portée) et elle ne peut pas être touchée par le constructeur.

3
Jason Punyon

Je sais, cela ne répond pas au pourquoi de votre question. Quoi qu'il en soit, ceux qui liront cette question pourraient néanmoins apprécier le code ci-dessous.

Si vous vous souciez vraiment de vous tirer une balle dans le pied lorsque vous remplacez 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 à l'échelle mondiale, 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 que rvar rInt = 5 mais ça marche.

1
Mike de Klerk

c # a déjà une var 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 être moins de code à écrire. Mais le 2ème extrait rendra la lecture seule explicite, lors du référencement de la variable.

0
Wolfgang Grinfeld

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 dans le .csx format de script.

0
Colonel Panic