2010-01-30 3 views
31

Этот вопрос возник в комментариях this answer. Невозможность иметь свойства readonly была предложена в качестве потенциальной причины использовать поля вместо свойств.Почему свойства не могут быть прочитаны только?

Например:

class Rectangle 
{ 
    private readonly int _width; 
    private readonly int _height; 

    public Rectangle(int width, int height) 
    { 
     _width = width; 
     _height = height; 
    } 

    public int Width { get { return _width; } } 
    public int Height { get { return _height; } } 
} 

Но почему вы не можете просто сделать это?

public int Width { get; readonly set; } 

Edit (осветление): Вы можете достичь этой функциональности в первом примере. Но почему вы не можете использовать автоматически реализованное сокращение свойств, чтобы сделать то же самое? Это также было бы менее беспорядочно, поскольку вам не приходилось напрямую обращаться к полям в вашем конструкторе; весь доступ будет через собственность.

+7

Лучшим синтаксисом будет 'public int Width {get; набор только для чтения; } '. – jason

+0

@ Джейсон: Кажется, это лучше - я отредактировал его к вашей версии. –

+3

@ Джейсон: Я не знаю, что-то о концепции «только для чтения сеттера» кажется мне очень странным. Здесь легко понять, в контексте этого вопроса, но я думаю, что если бы я увидел это неожиданно, это был бы момент WTF. – Aaronaught

ответ

22

Потому что язык этого не позволяет.

Это может показаться легкомысленным ответ: в конце концов, разработчики языка могли заявили, что если вы использовали readonly на автоматическую собственности, то это будет означать «свойство настраиваемое, но только в конструкторе».

Но функции не предоставляются бесплатно. (Эрик Ганннерс выражает это как «Каждая функция начинается с minus 100 points».) Чтобы реализовать автоматические свойства только для чтения, потребовалось бы дополнительное усилие компилятора для поддержки модификатора readonly для свойства (оно применимо только к полям), чтобы создать соответствующую поддержку и преобразовать sets свойства в присвоения поля поддержки. Это небольшая работа, чтобы поддержать то, что пользователь мог бы сделать достаточно легко, объявив поле для чтения в режиме readonly и создав однострочный getter, и эта работа будет стоить с точки зрения не реализации других функций.

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

+1

Это Эрик Гуннерсон, который говорит, что: http://blogs.msdn.com/ericgu/archive/2004/01/12/57985.aspx. В противном случае, отличный пост и правильный ответ. – jason

+1

Спасибо за исправление и ссылку, Джейсон - обновлено. – itowlson

+6

Это был последний. Это было в списке с C# 3. Мы хотели бы это сделать, но никогда не было достаточно высокого приоритета. Мы придумываем буквально сотни идей для новых функций языка, и мы можем сделать только пару из них в каждой версии. –

15

Если вы хотите сделать недвижимость «только для чтения» в том, что касается функциональности, вы делаете это, предоставляя только метод get, как указано в сообщении.

public int Width { get { return _width; } } 
public int Height { get { return _height; } } 

Компилятор будет даже ссылаться на них как «только на чтение», если вы попытаетесь написать им.

Имея дополнительный срок readonly для имущества, столкнулся бы с предоставлением метода set. Мне кажется, что это плохой синтаксис, т. Е. Как человек, читающий его (или компилятор, если на то пошло) знает, что имеет преимущество: readonly или set?

Кроме того, как пояснялось в ответе, на который вы ссылаетесь, readonly применяется только к полям и лимитам, записывающим эти поля в экземпляр класса. Со свойствами вы не можете писать им (я не думаю) даже внутри конструктора, если у них есть только метод get.

+2

Вы правы, что это обеспечивает ту же функциональность. Вот почему он был включен в качестве примера. Мой вопрос: почему вы не можете использовать автоматически реализованное сокращение свойств, чтобы сделать то же самое? Это также было бы менее беспорядочно, поскольку вам не приходилось напрямую обращаться к полям в вашем конструкторе; весь доступ будет через собственность. –

+1

@Matthew уверен, возможно, команда, ответственная за компилятор C# * могла бы пойти по этому пути, но разве это не будет более запутанным? Как объяснил @Nate, у вас может быть свойство «readonly», просто не автоматическое, что имеет смысл. Хотя может быть * возможным * достичь того, о чем вы говорите, я думаю, что это будет путать (я, например, смущен). –

2

Свойства может быть доступным только для чтения, а не автоматическими свойствами.

Идентификаторы get и set необходимы для автоматических свойств, и нет смысла для свойства, доступного только для чтения, иметь set.

Вы можете задать регулярное свойство как свойство только для чтения, только Определяя get - однако, даже если требование для обоих get и set для автоматических свойств не существует - свойство только для чтения не может быть автоматически определяется, потому что вам нужно знать поле поддержки, чтобы иметь возможность устанавливать его значение внутри (т. е. через конструктор).

Я полагаю, что в генерации кода может быть шаблон/макрос или что-то определенное в VS, но оно не может быть частью самого языка.

+0

Было бы совершенно логично, если бы компилятор разрешил синтаксис инициализатора поля с автоматическим свойством только для чтения, по крайней мере для полей, которые не реализуют 'IDisposable'. – supercat

9

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

public bool Property {get; private set;} 

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

+9

Это не та же семантика, что и 'readonly'. – jason

+0

Это правда, однако свойство, не имеющее сеттера или частный сеттер, по-прежнему собирает ошибку времени компиляции и предотвращает изменение значения, поэтому, если нет чего-то, что у меня отсутствует, и отсутствие сеттера функционально эквивалентно – Crippledsmurf

+2

Он не будет препятствовать модификации значения внутри класса вне конструктора. – ICR

1

Я думаю, что в основном проблема заключается в том, что свойства - это просто синтаксический сахар для поля с дополнительными методами getter/setter. Автоматические свойства генерируют поле поддержки так, чтобы они требовали «setter», или не было бы способа установить значение поля поддержки. Поскольку свойства действительно сопоставляются с методами, а не с полями, нет смысла делать их readonly.

Даже если разрешено, readonly может применяться только к автоматическим свойствам. Для традиционных свойств вы можете поместить произвольный код как в getter, так и в setter. Даже если установщик мог быть вызван только в конструкторе класса, геттер все же мог бы изменить значение, основанное на любой логике, которую вы решили вставить в нее. Это полностью противоречило бы концепции readonly, что потребовало бы разных правил синтаксиса и поддержки автоматических/традиционных свойств. Поскольку существует механизм - использование традиционных свойств только с определенным геттером и поле для чтения только для чтения, как в ссылочном вопросе, - я не вижу смысла в том, чтобы сбрасывать синтаксис свойств и потенциально создавать путаницу для чего-то с довольно простой и простой реализацией используя существующие языковые конструкции.

+0

очень хорошая точка - «Поскольку свойства действительно сопоставляются с методами, а не с полями, не имеет смысла делать их только для чтения». –

+2

@tvanfosson, @Ben McCormack: Это абсолютно неверно. Что случилось с 'public int Width {get; набор только для чтения; } 'отображение в' readonly int _width; public int Width {get {return _width; }} 'и' Width = 17' являются законными только в конструкторе? – jason

+0

@ Джейсон, возможно, я что-то пропустил, но я не понимаю, что вы говорите. Я не верю, что он (или я) говорит, что вам не следует настраивать свойства, которым не нужен метод 'set' (тем самым делая их« readonly »при компиляции). Он говорит, что ** ключевое слово ** 'readonly' может применяться только к полям, а не к методам (и, следовательно, к свойствам по расширению). –

0

Если Свойс есть отдельный набор, то это только для чтения от внешнего мира, а именно:

string _name; 
public string Name 
{ 
    get{ return _name; } 
    private set { _name = value; } 
} 

Или это может быть сделано только для чтения, если он не имеет сеттер вообще, то есть:

string _name; 
public string Name 
{ 
    get{ return _name; } 
} 
Смежные вопросы