Рейтинговые книги
Читем онлайн Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 74 75 76 77 78 79 80 81 82 ... 407
class="code">}

Теперь предположим, что создан объект Employee по имени joe. Необходимо сделать так, чтобы в день рождения сотрудника возраст увеличивался на 1 год. Используя традиционные методы set и get, пришлось бы написать приблизительно такой код:

Employee joe = new Employee();

joe.SetAge(joe.GetAge() + 1);

Тем не менее, если empAge инкапсулируется посредством свойства по имени Age, то код будет проще:

Employee joe = new Employee();

joe.Age++;

Свойства как члены, сжатые до выражений (нововведение в версии 7.0)

Как упоминалось ранее, методы set и get свойств также могут записываться в виде членов, сжатых до выражений. Правила и синтаксис те же: однострочные методы могут быть записаны с применением нового синтаксиса. Таким образом, свойство Age можно было бы переписать следующим образом:

public int Age

{

  get => empAge;

  set => empAge = value;

}

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

Использование свойств внутри определения класса

Свойства, в частности их порция set, являются общепринятым местом для размещения бизнес-правил класса. В текущий момент класс Employee имеет свойство Name, которое гарантирует, что длина имени не превышает 15 символов. Остальные свойства (ID, Рау и Age) также могут быть обновлены соответствующей логикой.

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

public Employee(string name, int age, int id, float pay)

{

  /// Похоже на проблему. ..

  if (name.Length > 15)

  {

    Console.WriteLine("Error! Name length exceeds 15 characters!");

                    // Ошибка! Длина имени превышает 15 символов!

  }

  else

  {

    _empName = name;

  }

  _empId = id;

  _empAge = age;

  _currPay = pay;

}

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

public Employee(string name, int age, int id, float pay)

{

   // Уже лучше! Используйте свойства для установки данных класса.

   // Это сократит количество дублированных проверок на предмет ошибок.

   Name = name;

   Age = age;

   ID = id;

   Pay = pay;

}

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

class Employee

{

  // Поля данных.

  private string _empName;

  private int _empId;

  private float _currPay;

  private int _empAge;

  // Конструкторы.

  public Employee() { }

  public Employee(string name, int id, float pay)

    :this(name, 0, id, pay){}

  public Employee(string name, int age, int id, float pay)

  {

    Name = name;

    Age = age;

    ID = id;

    Pay = pay;

  }

  // Методы.

  public void GiveBonus(float amount) => Pay += amount;

  public void DisplayStats()

  {

    Console.WriteLine("Name: {0}", Name); // имя сотрудника

    Console.WriteLine("ID: {0}", Id);

                    // идентификационный номер сотрудника

    Console.WriteLine("Age: {0}", Age);   // возраст сотрудника

    Console.WriteLine("Pay: {0}", Pay);   // текущая выплата

  }

  // Свойства остаются прежними...

  ...

}

Свойства, допускающие только чтение

При инкапсуляции данных может возникнуть желание сконфигурировать свойство, допускающее только чтение, для чего нужно просто опустить блок set. Например, пусть имеется новое свойство по имени SocialSecurityNumber, которое инкапсулирует закрытую строковую переменную empSSN. Вот как превратить его в свойство, доступное только для чтения:

public string SocialSecurityNumber

{

  get { return _empSSN; }

}

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

public string SocialSecurityNumber => _empSSN;

Теперь предположим, что конструктор класса принимает новый параметр, который дает возможность указывать в вызывающем коде номер карточки социального страхования для объекта, представляющего сотрудника. Поскольку свойство SocialSecurityNumber допускает только чтение, устанавливать значение так, как показано ниже, нельзя:

public Employee(string name, int age, int id, float pay, string ssn)

{

   Name = name;

   Age = age;

   ID = id;

   Pay = pay;

   // Если свойство предназначено только для чтения, это больше невозможно!

   SocialSecurityNumber = ssn;

}

Если только вы не готовы переделать данное свойство в поддерживающее чтение и запись (что вскоре будет сделано), тогда единственным вариантом со свойствами, допускающими только чтение, будет применение лежащей в основе переменной-члена empSSN внутри логики конструктора:

public Employee(string name, int age, int id, float pay, string ssn)

{

   ...

   // Проверить надлежащим образом входной параметр ssn

   // и затем установить значение.

   empSSN = ssn;

}

Свойства, допускающие только запись

 Если вы хотите сконфигурировать свойство как допускающее только

1 ... 74 75 76 77 78 79 80 81 82 ... 407
На этой странице вы можете бесплатно читать книгу Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен бесплатно.

Оставить комментарий