Язык программирования C#9 и платформа .NET5
Часть 118 из 642 Информация о книге
Employee emp = new Employee("Marvin", 456, 30_000);emp.GiveBonus(1000);emp.DisplayStats();// Использовать методы get/set для взаимодействия// с именем сотрудника, представленного объектом.emp.SetName("Marv");Console.WriteLine("Employee is named: {0}", emp.GetName());Console.ReadLine();Благодаря коду в методе
попытка указать для имени строку, содержащую более 15 символов (как показано ниже), приводит к выводу на консоль жестко закодированного сообщения об ошибке:SetName()Console.WriteLine("***** Fun with Encapsulation *****\n");...<b>// Длиннее 15 символов! На консоль выводится сообщение об ошибке.</b>Employee emp2 = new Employee();emp2.SetName("Xena the warrior princess");Console.ReadLine();Пока все идет хорошо. Мы инкапсулировали закрытое поле
с использованием двух открытых методов с именамиempNameиGetName(). Для дальнейшей инкапсуляции данных в классеSetName()понадобится добавить разнообразные дополнительные методы (такие какEmployee,GetID(),SetID(),GetCurrentPay()). В каждом методе, изменяющем данные, может содержаться несколько строк кода, в которых реализована проверка дополнительных бизнес-правил. Несмотря на то что это определенно достижимо, для инкапсуляции данных класса в языке C# имеется удобная альтернативная система записи.SetCurrentPay()Инкапсуляция с использованием свойств
Хотя инкапсулировать поля данных можно с применением традиционной пары методов
иget, в языках .NET Core предпочтение отдается обеспечению инкапсуляции данных с использованием свойств. Прежде всего, имейте в виду, что свойства — всего лишь контейнер для "настоящих" методов доступа и изменения, именуемыхsetиgetсоответственно. Следовательно, проектировщик класса по-прежнему может выполнить любую внутреннюю логику перед присваиванием значения (например, преобразовать в верхний регистр, избавиться от недопустимых символов, проверить вхождение внутрь границ и т.д.).setНиже приведен измененный код класса
, который теперь обеспечивает инкапсуляцию каждого поля с использованием синтаксиса свойств вместо традиционных методовEmployeeиget.setclass Employee{// Поля данных.private string _empName;private int _empId;private float _currPay;<b> // Свойства!</b><b> public string Name</b><b> {</b><b> get { return _empName; }</b><b> set</b><b> {</b><b> if (value.Length > 15)</b><b> {</b><b> Console.WriteLine("Error! Name length exceeds 15 characters!");</b><b> // Ошибка! Длина имени превышает 15 символов!</b><b> }</b><b> else</b><b> {</b><b> _empName = value;</b><b> }</b><b> }</b><b> }</b>// Можно было бы добавить дополнительные бизнес-правила для установки// данных свойств, но в настоящем примере в этом нет необходимости.<b> public int Id</b><b> {</b><b> get { return _empId; }</b><b> set { _empId = value; }</b><b> }</b><b> public float Pay</b><b> {</b><b> get { return _currPay; }</b><b> set { _currPay = value; }</b><b> }</b>...}Свойство C# состоит из определений областей
(метод доступа) иget(метод изменения) прямо внутри самого свойства. Обратите внимание, что свойство указывает тип инкапсулируемых им данных способом, который выглядит как возвращаемое значение. Кроме того, в отличие от метода при определении свойства не применяются круглые скобки (даже пустые). Взгляните на следующий комментарий к текущему свойствуset:Id// int представляет тип данных, инкапсулируемых этим свойством.public int Id // Обратите внимание на отсутствие круглых скобок.{get { return _empId; }set { _empID = value; }}В области видимости
свойства используется лексемаset, которая представляет входное значение, присваиваемое свойству вызывающим кодом. Лексемаvalueне является настоящим ключевым словом С#, а представляет собой то, что называется контекстным ключевым словом. Когда лексемаvalueнаходится внутри областиvalue, она всегда обозначает значение, присваиваемое вызывающим кодом, и всегда имеет тип, совпадающий с типом самого свойства. Таким образом, вот как свойствоsetможет проверить допустимую длину строки:Name