Почему C # запрещает чтение только локальных переменных? - PullRequest
102 голосов
/ 14 января 2009

Дружеская дискуссия с коллегой по этому поводу. У нас есть какие-то мысли по этому поводу, но нам интересно, что об этом думает SO-группа?

Ответы [ 13 ]

51 голосов
/ 29 апреля 2011

Я думаю, что это плохое суждение со стороны архитекторов C #. модификатор readonly для локальных переменных помогает поддерживать корректность программы (точно так же, как утверждает) и потенциально может помочь компилятору оптимизировать код (по крайней мере, в случае других языков). Тот факт, что это запрещено в C # прямо сейчас, является еще одним аргументом в пользу того, что некоторые «особенности» C # являются всего лишь применением стиля личного кодирования его создателей.

33 голосов
/ 14 января 2009

Обращаясь к ответу Джареда, это, вероятно, просто должна быть функция времени компиляции - компилятор запретит вам записывать в переменную после первоначального объявления (которое должно включать в себя присваивание).

Могу ли я увидеть ценность в этом? Потенциально - но не много, если честно. Если вы не можете легко определить, будет ли переменная назначена в другом месте метода, значит ваш метод слишком длинный.

Для чего бы то ни было, в Java есть эта функция (с использованием модификатора final), и я очень редко видел, что она используется, за исключением случаев, когда имеет используется, чтобы позволить переменной быть захваченной анонимным внутренним классом - и там, где она используется , это создает впечатление беспорядка, а не полезной информации.

19 голосов
/ 06 декабря 2017

Предложение только для чтения местных жителей и параметров для было кратко обсуждено командой разработчиков C # 7. От Примечания к совещанию по проектированию в C # за 21 января 2015 года :

Параметры и локальные объекты могут быть захвачены лямбдами и, таким образом, доступны одновременно, но нет способа защитить их от проблем совместного использования состояний: они не могут быть прочитаны только.

Как правило, большинство параметров и многие локальные объекты никогда не предназначены для назначения после получения их начального значения. Разрешение на чтение только для них ясно выразит это намерение.

Одна проблема заключается в том, что эта функция может быть "привлекательной неприятностью". Принимая во внимание, что «правильная вещь» почти всегда состоит в том, чтобы сделать параметры и локальные параметры доступными только для чтения, для этого будет значительно загроможден код.

Идея частично смягчить это состоит в том, чтобы разрешить сжатие комбинации readonly var для локальной переменной в val или что-то в этом роде. В более общем смысле мы можем попытаться просто придумать более короткое ключевое слово, чем установленное только для чтения, чтобы выразить «только для чтения».

Обсуждение продолжается в репозитории C # Language Design. Проголосуйте, чтобы показать свою поддержку. https://github.com/dotnet/csharplang/issues/188

15 голосов
/ 14 января 2009

Одной из причин является отсутствие поддержки CLR для локального чтения. Readonly переводится в код операции инициализации CLR / CLI. Этот флаг может применяться только к полям и не имеет значения для локального. На самом деле, применение его к локальному может привести к непроверяемому коду.

Это не значит, что C # не может этого сделать. Но это дало бы два разных значения одной и той же языковой конструкции. Версия для местных жителей не будет иметь эквивалента CLR.

7 голосов
/ 14 января 2009

Я был тем сотрудником, и он не был дружелюбным! (шучу)

Я бы не исключал эту функцию, потому что лучше писать короткие методы. Это все равно что сказать, что вы не должны использовать потоки, потому что они сложные. Дай мне нож и позволь мне не отвечать за себя.

Лично я хотел использовать другое ключевое слово типа var, например inv (invarient) или rvar, чтобы избежать беспорядка. Я изучал F # в последнее время и нашел неизменную вещь привлекательной.

Никогда не знал, что у Java это есть.

5 голосов
/ 05 августа 2017

Это упущение для дизайнера языка c #. F # имеет ключевое слово val, и оно основано на CLR. Нет причин, по которым C # не может иметь такую ​​же функцию языка.

5 голосов
/ 30 апреля 2012

Я бы хотел, чтобы локальные только для чтения переменные были такими же, как мне нравятся локальные const переменные. Но это имеет меньший приоритет, чем другие темы.
Возможно, его приоритет является той же причиной, по которой дизайнеры C # не (пока!) реализуют эту функцию. Но в будущих версиях должно быть легко (и обратно совместимо) поддерживать локальные переменные только для чтения.

3 голосов
/ 14 января 2009

Только чтение означает, что единственное место, в котором можно установить переменную экземпляра, находится в конструкторе. При локальном объявлении переменной у нее нет экземпляра (она находится только в области видимости), и конструктор не может коснуться ее.

1 голос
/ 03 сентября 2015

Я знаю, это не отвечает на вопрос почему. В любом случае, тем, кто читает этот вопрос, может понравиться приведенный ниже код.

Если вы действительно заинтересованы в том, чтобы выстрелить себе в ногу при переопределении локальной переменной, которую следует устанавливать только один раз, и вы не хотите делать ее более доступной в глобальном масштабе, вы можете сделать что-то подобное. 1003 *

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

Пример использования:

        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

Возможно, не такой код, как rvar rInt = 5, но он работает.

0 голосов
/ 15 марта 2019

c # уже имеет переменную только для чтения, хотя и в несколько ином синтаксисе:

Рассмотрим следующие строки:

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

Сравнить с:

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

По общему признанию, первое решение могло бы быть меньшим количеством кода, чтобы написать. Но второй фрагмент сделает явным только чтение, когда ссылается на переменную.

...