Подтвердить что ты не робот

Переменная, которая не может быть изменена

Разрешает ли С# переменную, которая не может быть изменена? Это как const, но вместо того, чтобы присваивать ему значение в объявлении, переменная не имеет значения по умолчанию, но ей может быть присвоено значение только один раз во время выполнения (EDIT: и, возможно, не от конструктора). или это невозможно?

4b9b3361

Ответ 1

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

public class SetValueOnce<T>
{
    public bool _set;
    private T _value;

    public SetValueOnce()
    { 
      _value = default(T);
      _set = false;
    }

    public SetValueOnce(T value)
    { 
      _value = value;
      _set = true;
    }

    public T Value
    {
      get
      {
          if(!_set)
             throw new Exception("Value has not been set yet!");
          return _value;
      {
      set
      {
         if(_set)
             throw new Exception("Value already set!");
         _value = value;
         _set = true;
      }
   }
}

Ответ 2

Да, в С# есть несколько способов сделать это.

Во-первых, что такое "переменная"? Переменная - это место хранения. Локальные переменные, формальные параметры методов (и индексаторы, конструкторы и т.д.), Статические поля и экземпляры, элементы массива и разметки указателя - все переменные.

Некоторые переменные могут быть объявлены как "readonly". Переменная "readonly" может быть изменена только один раз, либо инициализатором в объявлении, либо в конструкторе. Только декларации полей могут быть прочитаны только; С# не поддерживает объявленные пользователем локали только для чтения.

Существуют определенные ограничения на переменные readonly, которые помогают гарантировать, что нормальная работа С# не вносит мутации. Это может привести к неожиданным результатам! См

http://ericlippert.com/2008/05/14/mutating-readonly-structs/

для деталей.

Некоторые локальные жители также эффективно читают. Например, когда вы говорите using(Stream s = whatever), то внутри встроенного оператора using вы не можете изменить значение s. Причиной этого ограничения является предотвращение ошибки, при которой вы создаете ресурс, который должен быть удален, а затем утилизировать другой ресурс, когда содержимое переменной s расположено. Лучше быть тем же самым.

(К сожалению, в С# есть ошибки, связанные с ситуацией, когда выделенный ресурс является типом структуры, структура имеет метод, который мутирует структуру, а локальная переменная является или не является закрытой локалью анонимной функции или блок итератора, так как сценарии неясны, и исправление будет потенциально ломающимся, мы еще ничего не сделали об этом, ожидая дальнейшего анализа.)

Локальная переменная, объявленная в операторе foreach, также эффективно readonly - эта переменная меняет значение каждый раз через цикл, но вы не можете изменить его значение.

Невозможно сделать формальный параметр readonly, элемент массива или разыменование указателя.

Существуют различные способы "разбить" ограничение на чтение и записать в переменную, которая должна быть только для чтения. Вы можете использовать Reflection или небезопасный код, чтобы существенно сократить любое ограничение безопасности CLR, если у вас есть достаточные привилегии для этого. Если это причиняет боль, когда вы это делаете, не делайте этого; с этими полномочиями лежит ответственность за то, что вы делаете, и делайте это правильно.

Ответ 3

Вы можете объявить переменную readonly, которая может быть установлена ​​только в конструкторе или непосредственно через его объявление.

Ответ 4

Вы можете использовать свой собственный пользовательский настройщик (но не используйте Object, если вам не нужно, выберите правильный класс):

private Object myObj = null;
private Boolean myObjSet = false;

public Object MyObj
{
    get { return this.myObj; }
    set 
    { 
        if (this.myObjSet) throw new InvalidOperationException("This value is read only");
        this.myObj = value;
        this.myObjSet = true;
    }
}

EDIT:

Это не останавливает изменение частного поля внутренними классами.

Ответ 5

Конечно. Вы можете использовать readonly:

I.e.: public readonly int z;

Это может быть изменено только внутри конструктора.

От MSDN:

Вы можете назначить значение для поля только для чтения только в следующих контекстах:

Когда переменная инициализируется в объявлении, например:

  • public readonly int y = 5;

  • Для поля экземпляра в конструкторах экземпляра класса, который содержит объявление поля, или для статического поля, в статическом конструкторе класса, который содержит объявление поля. Это также единственные контексты, в которых допустимо передать поле readonly в качестве параметра out или ref.

Если вы хотите создать свойство, которое может быть изменено только внутри созданного класса, вы можете использовать следующее:

public string SetInClass
{
   get;
   private set;
}

Это позволяет внести изменения в класс, но переменная не может быть изменена вне класса.

Ответ 7

Можно пометить поле readonly, которое потребует, чтобы вы установили его как в точке объявления, так и в конструкторе, а затем помешали ему переназначить постконструкцию.

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

Ответ 8

Поскольку вопрос аналогичный вопрос был недавно задан @Ivan, позвольте мне предложить еще один метод конечно, более точно, с поддержкой универсального конструктора.

public class Immutable<T> {
    public T Val { get; private set; }
    public Immutable(T t) {
        Val = t;
    }
}

Использование будет

var immutableInt1 = new Immutable<int>(3); // you can set only once
immutableInt1.Val = 5; // compile error here: set inaccessible
Console.WriteLine("value: " + immutableInt1.Val);

Дело в том, что теперь вы получаете ошибку компиляции, если пытаетесь установить новое значение.

Кроме того, я считаю, что вам лучше использовать функциональный язык, например F #, вместо С#, если вы хотите следовать этой парадигме.

Ответ 9

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

private myVariable = null;
public object MyVariable
{
   get { return myVariable; }
   set { if(myVariable == null ) myVariable = value;
}