Чтобы протестировать внесенные обновления, добавьте к операторам верхнего уровня следующий код:
Employee emp = new Employee("Marvin",45,123,1000,"111-11-1111",
EmployeePayTypeEnum.
Salaried);
Console.WriteLine(emp.Pay);
emp.GiveBonus(100);
Console.WriteLine(emp.Pay);
Понятие автоматических свойств
При создании свойств для инкапсуляции данных часто обнаруживается, что области set
содержат код для применения бизнес-правил программы. Тем не менее, в некоторых случаях нужна только простая логика извлечения или установки значения. В результате получается большой объем кода следующего вида:
// Тип Car, использующий стандартный синтаксис свойств.
class Car
{
private string carName = "";
public string PetName
{
get { return carName; }
set { carName = value; }
}
}
В подобных случаях многократное определение закрытых поддерживающих полей и простых свойств может стать слишком громоздким. Например, при построении класса, которому нужны девять закрытых элементов данных, в итоге получаются девять связанных с ними свойств, которые представляют собой не более чем тонкие оболочки для служб инкапсуляции.
Чтобы упростить процесс обеспечения простой инкапсуляции данных полей, можно использовать синтаксис автоматических свойств. Как следует из названия, это средство перекладывает работу по определению закрытых поддерживающих полей и связанных с ними свойств C# на компилятор за счет применения небольшого нововведения в синтаксисе. В целях иллюстрации создайте новый проект консольного приложения по имени AutoProps
и добавьте к нему файл Car.cs
с переделанным классом Car
, в котором данный синтаксис используется для быстрого создания трех свойств:
using System;
namespace AutoProps
{
class Car
{
// Автоматические свойства! Нет нужды определять поддерживающие поля.
public string PetName { get; set; }
public int Speed { get; set; }
public string Color { get; set; }
}
}
На заметку! Среды Visual Studio и Visual Studio Code предоставляют фрагмент кода prop
. Если вы наберете слово prop
внутри определения класса и нажмете клавишу <ТаЬ>, то IDE-среда сгенерирует начальный код для нового автоматического свойства. Затем с помощью клавиши <ТаЬ> можно циклически проходить по всем частям определения и заполнять необходимые детали. Испытайте описанный прием.
При определении автоматического свойства вы просто указываете модификатор доступа, лежащий в основе тип данных, имя свойства и пустые области get/set
. Во время компиляции тип будет оснащен автоматически сгенерированным поддерживающим полем и подходящей реализацией логики get/set
.
На заметку! Имя автоматически сгенерированного закрытого поддерживающего поля будет невидимым для вашей кодовой базы С#. Просмотреть его можно только с помощью инструмента вроде ildasm.exe
.
Начиная с версии C# 6, разрешено определять "автоматическое свойство только для чтения", опуская область set
. Автоматические свойства только для чтения можно устанавливать только в конструкторе. Тем не менее, определять свойство, предназначенное только для записи, нельзя. Вот пример:
// Свойство только для чтения? Допустимо!
public int MyReadOnlyProp { get; }
// Свойство только для записи? Ошибка!
public int MyWriteOnlyProp { set; }
Взаимодействие с автоматическими свойствами
Поскольку компилятор будет определять закрытые поддерживающие поля на этапе компиляции (и учитывая, что эти поля в коде C# непосредственно не доступны), в классе, который имеет автоматические свойства, для установки и чтения лежащих в их основе значений всегда должен применяться синтаксис свойств. Указанный факт важно отметить, т.к. многие программисты напрямую используют закрытые поля внутри определения класса, что в данном случае невозможно. Например, если бы класс Car
содержал метод DisplayStats()
, то в его реализации пришлось бы применять имена свойств:
class Car
{
// Автоматические свойства!