Выбрать главу

Хотя инкапсулировать поля данных можно с применением традиционной пары методов get и set, в языках .NET Core предпочтение отдается обеспечению инкапсуляции данных с использованием свойств. Прежде всего, имейте в виду, что свойства — всего лишь контейнер для "настоящих" методов доступа и изменения, именуемых get и set соответственно. Следовательно, проектировщик класса по-прежнему может выполнить любую внутреннюю логику перед присваиванием значения (например, преобразовать в верхний регистр, избавиться от недопустимых символов, проверить вхождение внутрь границ и т.д.).

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

class Employee

{

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

  private string _empName;

  private int _empId;

  private float _currPay;

  // Свойства!

  public string Name

  {

    get { return _empName; }

    set

    {

      if (value.Length > 15)

      {

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

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

      }

      else

      {

        _empName = value;

      }

    }

  }

  // Можно было бы добавить дополнительные бизнес-правила для установки

  // данных свойств, но в настоящем примере в этом нет необходимости.

  public int Id

  {

    get { return _empId; }

    set { _empId = value; }

  }

  public float Pay

  {

    get { return _currPay; }

    set { _currPay = value; }

  }

...

}

Свойство C# состоит из определений областей get (метод доступа) и set (метод изменения) прямо внутри самого свойства. Обратите внимание, что свойство указывает тип инкапсулируемых им данных способом, который выглядит как возвращаемое значение. Кроме того, в отличие от метода при определении свойства не применяются круглые скобки (даже пустые). Взгляните на следующий комментарий к текущему свойству Id:

// int представляет тип данных, инкапсулируемых этим свойством.

public int Id // Обратите внимание на отсутствие круглых скобок.

{

  get { return _empId; }

  set { _empID = value; }

}

В области видимости set свойства используется лексема value, которая представляет входное значение, присваиваемое свойству вызывающим кодом. Лексема value не является настоящим ключевым словом С#, а представляет собой то, что называется контекстным ключевым словом. Когда лексема value находится внутри области set, она всегда обозначает значение, присваиваемое вызывающим кодом, и всегда имеет тип, совпадающий с типом самого свойства. Таким образом, вот как свойство Name может проверить допустимую длину строки:

public string Name

{

  get { return _empName; }

  set

  {

    // Здесь value на самом деле имеет тип string.

    if (value.Length > 15)

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

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

    }

    else

    {

      empName = value;

    }

  }

}

После определения свойств подобного рода вызывающему коду кажется, что он имеет дело с открытым элементом данных однако "за кулисами" при каждом обращении к ним вызывается корректный блок get или set, предохраняя инкапсуляцию:

Console.WriteLine("***** Fun with Encapsulation *****\n");

Employee emp = new Employee("Marvin", 456, 30000);

emp.GiveBonus(1000);

emp.DisplayStats();

// Переустановка и аатем получение свойства Name.

emp.Name = "Marv";

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