2017-01-27 27 views
1

Я видел ответ Marc Gravell от 8 '09 мая в 13:29 :Есть ли способ установить свойство только один раз в качестве встроенного механизма?

public sealed class WriteOnce<T> 
{ 
    private T value; 
    private bool hasValue; 
    public override string ToString() 
    { 
     return hasValue ? Convert.ToString(value) : ""; 
    } 
    public T Value 
    { 
     get 
     { 
      if (!hasValue) throw new InvalidOperationException("Value not set"); 
      return value; 
     } 
     set 
     { 
      if (hasValue) throw new InvalidOperationException("Value already set"); 
      this.value = value; 
      this.hasValue = true; 
     } 
    } 
    public T ValueOrDefault { get { return value; } } 

    public static implicit operator T(WriteOnce<T> value) { return value.Value; } 
} 
Then use, for example: 

readonly WriteOnce<string> name = new WriteOnce<string>(); 
public WriteOnce<string> Name { get { return name; } } 

Но я не мог понять, почему бы один создать readonly WriteOnce<T>, если его значение равно private и он использует свойство Value, которое может быть установлено только один раз. Также я не мог получить, почему бы один создать свойство Name что только позволяет ГЭТ, но не набор так:

1.You не может установить значение зовут потому что она находится только для чтения и

2.Можно 't установить его значение через собственность, потому что это только получить.

ответ

1

Вы вводите в заблуждение немало вещей здесь.

  1. только для чтения поле означает, что он может быть только назначен внутри конструктора или через поле инициализатора. Теперь WriteOnce является ссылочным типом, поэтому присвоение означает, что значение, хранящееся в name, является ссылкой на вновь созданный объект WriteOnce<string>.

    Ничего не мешает вам делать все, что угодно name.Value = "Hello";, потому что вы не меняете значение name. name = whatever вне конструктора или инициализатора поля, с другой стороны, запрещается, потому что вы меняете значение переменной на новую ссылку, но ничего больше.

  2. Name является только для чтения свойство, которое имеет в качестве области подложки name.

    Только для чтения не позволяет делать Name = new WriteOnce<string>(), но Name.Value = "Hello" отлично подходит.

    Во всяком случае, Nowdays, вы бы просто использовать только для чтения autoproperty и пусть компилятор генерировать все сантехнические код (резервное поле):

    public WriteOnce<string> Name { get } 
    
+0

'public WriteOnce Name {get}' не даст вам возможности создать экземпляр в «читаемом» виде 'var instance = new WriteOnce {Name =" test "};' – Fabio

+0

@Fabio этот код даже не использует autoproperties Я почти уверен, что это довольно чертовски старый, и цель кода заключалась в том, что 'name' был задан с помощью аргумента конструктора. – InBetween

+0

Большое спасибо, ваше объяснение с объяснением @Tom сделало это действительно ясным для меня – WeinForce

1

readonly означает, что объект может быть создан только или изменено в конструкторе. Делать его только приватным, а не readonly, позволял бы любой метод для создания нового поля name. Поэтому верно, что вы можете установить Value только один раз, но если объект не читается, вы можете полностью заменить его новым.

Creatint readonly WriteOnce означает, что вы можете установить значение name в любое время, а не только в конструкторе, но как только вы установите значение, которое вы не можете изменить его, и вы не можете заменить его новым WriteOnce объекта.

0

Вы можете переписать класс как структуру, чтобы сделать его немного проще и легко читать.

struct WriteOnce<T> 
{ 
    public T Value { get; } 

    public WriteOnce(T input) 
    { 
     Value = input; 
    } 

    public static implicit operator WriteOnce<T>(T input) 
    { 
     return new WriteOnce<T>(input); 
    } 
} 

Использование:

WriteOnce<string> name = "test"; 

Вы можете изменить значение на конкретизации, так что вы всегда будете знать, что это будет.

+0

Ухаживать за голосом, чтобы я мог прояснить ситуацию лучше? Он отвечает на его титул. – Dispersia

+0

Создание 'WriteOnce' структуры не позволит вам сделать следующее:' SomeClass.Name.Value = "Hello"; '. Вы получите ошибку времени компиляции, потому что этот код не будет делать то, что вы ожидаете от него (что в принципе ничего не полезно): 'Невозможно изменить возвращаемое значение SomeClass.Name, потому что это не переменная. причины, по которым изменяемые структуры - что-то, чего следует избегать, просто советуя использовать их, стоит минус-голос. – InBetween

+0

Да ... вы не должны быть в состоянии. Это целая цель кода. Зачем вам это нужно? И эта структура неизменна ... что? ... – Dispersia