Авто-свойства C # 3.0 - полезно или нет? [закрыто]


155

Примечание: это было опубликовано, когда я начинал C #. Обладая знаниями 2014 года, я могу с уверенностью сказать, что авто-свойства являются одними из лучших вещей, которые когда-либо случались с языком C #.

Я привык создавать свои свойства в C #, используя закрытое и открытое поле:

private string title;
public string Title
{
    get { return title;  }
    set { title = value;  }
}

Теперь, с .NET 3.0, мы получили авто-свойства:

public string Title { get; set; }

Я знаю, что это скорее философский / субъективный вопрос, но есть ли причина использовать эти авто-свойства, кроме как сохранить пять строк кода для каждого поля? Моя личная неприятность заключается в том, что эти свойства скрывают от меня вещи, и я не большой поклонник черной магии.

На самом деле скрытое приватное поле даже не отображается в отладчике, что нормально, учитывая тот факт, что функции get / set ничего не делают. Но когда я хочу реализовать некоторую логику получения / установки, я все равно должен использовать пару приват / публич.

Я вижу преимущество в том, что я сохраняю много кода (одна против шести строк), не теряя возможности изменить логику получения / установки позже, но опять же я уже могу это сделать, просто объявив открытое поле «Публичная строка заголовка» без необходимость {получить; устанавливать; } блок, таким образом, даже сохраняя больше кода.

Итак, что мне здесь не хватает? Почему кто-то на самом деле хочет использовать авто-свойства?


86
«Моя личная неприятность в том, что эти свойства скрывают вещи от меня, и я не большой поклонник черной магии». А? Вы знаете, что компилятор постоянно скрывает от вас тонну, верно? Если вы не пишете ассемблер (или, точнее, фактические 1 и 0 для вашего кода), ВСЕ, что вы пишете, скрывает от вас вещи.
Чарльз Боунг

Ответы:



62

Да, он просто сохраняет код. Это намного легче читать, когда у вас их много. Их быстрее написать и легче поддерживать. Сохранение кода всегда хорошая цель.

Вы можете установить разные области:

public string PropertyName { get; private set; }

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

Начиная с C # 6 вы также можете создавать истинные readonlyсвойства - то есть неизменяемые свойства, которые нельзя изменить вне конструктора:

public string PropertyName { get; }

public MyClass() { this.PropertyName = "whatever"; }

Во время компиляции это станет:

readonly string pName;
public string PropertyName { get { return this.pName; } }

public MyClass() { this.pName = "whatever"; }

В неизменяемых классах с большим количеством членов это экономит много лишнего кода.


«Таким образом, вы не теряете никакой функциональности». как вы их отлаживаете?
вали

2
@wal - что там для отладки? С этой точки зрения вы в основном имеете дело с переменными-членами.
Кит

6
@wal - Вы можете поставить на них точку останова, так же как вы можете получить доступ к переменной-члену, вы просто не можете войти в них. Но почему вы хотите? То, что на самом деле делают авто-свойства, является как тривиальным, так и автоматически генерируемым, если у вас есть ошибки, это одно из мест, где они крайне маловероятны.
Кит

3
нам может понадобиться вынести это за пределы Кита. :)
wal

1
Но хорошо, предположим, у вас есть много вызовов setter для myObj.Title ... вы хотите увидеть, где значение меняется с «text» на null, то есть на условную точку останова. как ты этого добиваешься? Вы даже не можете установить точку останова на сеттере
wal

45

Три больших недостатка использования полей вместо свойств:

  1. Вы не можете привязать данные к полю, тогда как вы можете к свойству
  2. Если вы начинаете использовать поле, вы не можете позже (легко) изменить его на свойство
  3. Есть некоторые атрибуты, которые вы можете добавить в свойство, которое нельзя добавить в поле

7
«Если вы начинаете использовать поле, вы не можете позже (легко) изменить его на свойство», извините, но почему?
Homam

6
@Homam В основном, любой потребительский код, использующий отражение в ваших полях, сломается, поскольку им придется переключиться с использования FieldInfo на PropertyInfo.
WCWedin

8
@Homam Кроме того, изменение поля на свойство нарушает двоичную совместимость, требуя перекомпиляции всех потребителей поля.
Одрэйд

1
Помимо проблем с перекомпиляцией и отражением, очень легко инкапсулировать поля с помощью Visual Studio: Ctrl-R + E позволит вам превратить поле в свойство с соответствующими методами получения / установки. (или щелкните правой кнопкой мыши поле, измените коэффициент, инкапсулируйте поле).
JoeBrockhaus

Поля @Hommam являются lvalues ​​(они переменные), а свойства - нет. Материал, который мог скомпилироваться, когда это было поле, может не скомпилироваться, когда это свойство.
Марк

29

Я лично люблю авто-свойства. Что не так с сохранением строк кода? Если вы хотите что-то делать в методах получения или установки, в дальнейшем нет проблем преобразовать их в обычные свойства.

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

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

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


29

От Бьярне Страуструпа, создателя C ++:

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

И знаешь, что? Он прав. Как часто вы просто оборачиваете приватные поля в get и set, фактически ничего не делая внутри get / set, просто потому, что это «объектно-ориентированная» вещь, которую нужно сделать. Это решение Microsoft от проблемы; это в основном публичные поля, которые вы можете связать.


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

18

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

private readonly string title;
public string Title
{
    get { return this.title; }
}

(где поле инициализируется в конструкторе с помощью переданного параметра, а затем доступно только для чтения.)

Так что это имеет преимущества перед простым get/ private setautoproperty.


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

@Keith: Ваше первое предложение кажется фактически неверным.
Доменик

3
Не public string Title { get; private set; }приведет ли это к тому же результату? Конечно, вы сможете изменить его из класса, но если вы сделаете это, у вас возникнут другие проблемы ...: p
Свиш

2
@Svish - по этому аргументу никогда не следует использовать ключевое слово readonly в C #, поскольку его использование означало бы, что мы скрываем эти «разные проблемы»
Zaid Masud

2
Я просто имею в виду, что с точки зрения внешнего API это не будет иметь большого значения. И так, при желании можно использовать авто-свойства. Лучше всего, конечно, было бы, если бы вы могли сделать что-то вродеpublic string Title { get; private readonly set; }
Svish

12

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


8

Авто-свойства - такая же черная магия, как и все остальное в C #. Когда вы думаете об этом с точки зрения компиляции в IL, а не вначале для расширения до обычного свойства C #, это становится намного менее черной магией, чем многие другие языковые конструкции.


5

Я использую авто-свойства все время. До C # 3 я не мог возиться со всей типизацией и просто использовал вместо этого публичные переменные.

Единственное, чего мне не хватает, так это возможности:

public string Name = "DefaultName";

Вы должны перенести значения по умолчанию в ваши конструкторы со свойствами. нудно :-(


4
С помощью инициализаторов Auto-property из C # 6 вы скоро сможете это сделать: public string Name { get; set; } = "DefaultName"; blogs.msdn.com/b/csharpfaq/archive/2014/11/20/…
Карлос Муньос

5

Я думаю, что любая конструкция, которая интуитивно понятна и сокращает количество строк кода, является большим плюсом.

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

У Руби все это время было:

attr_accessor :my_property
attr_reader :my_getter
attr_writer :my_setter

2

Единственная проблема, которую я имею с ними, состоит в том, что они не зашли достаточно далеко. В том же выпуске компилятора, в котором добавлены автоматические свойства, добавлены частичные методы. Почему они не соединили их, мне не под силу. Простое «частичное On <PropertyName> Changed» сделало бы эти вещи действительно очень полезными.


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

2

Это просто, это коротко, и если вы хотите создать реальную реализацию внутри тела свойства где-то вниз по линии, это не нарушит внешний интерфейс вашего типа.

Так просто, как, что.


1

Здесь следует отметить, что, насколько я понимаю, это всего лишь синтаксический сахар на стороне C # 3.0, означающий, что IL, сгенерированный компилятором, одинаков. Я согласен с тем, чтобы избегать черной магии, но, тем не менее, меньшее количество строк для одной и той же вещи, как правило, хорошо.


1

На мой взгляд, вы всегда должны использовать авто-свойства вместо открытых полей. Тем не менее, вот компромисс:

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

  • нужен доступ к полю снаружи его сборки, или
  • необходимо прикрепить логику к получателю / установщику

Сделай это:

  1. переименовать поле
  2. сделать это частным
  3. добавить публичную собственность

Ваш код клиента не нужно будет менять.

Но когда-нибудь ваша система вырастет, и вы разложите ее на отдельные сборки и несколько решений. Когда это произойдет, любые открытые поля снова будут преследовать вас, потому что, как упоминал Джефф, изменение открытого поля на публичное свойство является критическим изменением API .


0

Я использую CodeRush, это быстрее, чем авто-свойства.

Сделать это:

 private string title;
public string Title
{
    get { return title;  }
    set { title = value;  }
}

Требуется всего восемь нажатий клавиш.


5
Если я удерживаю клавиши CTRL и V, я могу вставлять много-много вещей, / очень быстро /, но это не делает его «лучше». Как это отвечает на первоначальный вопрос?
JBRWilkinson

0

Хорошо с фрагментами кода, авто-свойство с тем же именем будет в общей сложности семь нажатий клавиш;)


0

@ Domenic: я не понимаю .. ты не можешь сделать это с авто-свойствами ?:

public string Title { get; }

или

public string Title { get; private set; }

Это то, что вы имеете в виду?


Вы можете (последнее; первое не будет компилироваться), но тогда поле не является неизменным внутри вашего объекта.
Доменик

Слово предостережения, только структуры являются неизменными, когда помечены только для чтения, классы просто не назначаются.
Guvante

0

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

Чего не хватает VS2008, так это рефактора взрыва Auto-Property .

Тот факт, что у нас есть рефактор инкапсулированных полей, ускоряет мою работу, просто используя открытые поля.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.