Лекция 5 Свойства и инкапсуляция

Кроме обычных методов в языке C# предусмотрены специальные методы доступа, которые называют свойства. Они обеспечивают простой доступ к полям класса, узнать их значение или выполнить их установку.

Стандартное описание свойства имеет следующий синтаксис:

[модификатор_доступа] возвращаемый_тип произвольное_название

{

           // код свойства

}

Например:

class Person

{

private string name;

 

public string Name

{

   get

   {

       return name;

   }

 

   set

   {

       name = value;

   }

}

}

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

Через это свойство мы можем управлять доступом к переменной name. Стандартное определение свойства содержит блоки get и set. В блоке get мы возвращаем значение поля, а в блоке set устанавливаем. Параметр value представляет передаваемое значение.

Мы можем использовать данное свойство следующим образом:

Person p = new Person();

 

// Устанавливаем свойство - срабатывает блок Set

// значение "Tom" и есть передаваемое в свойство value

p.Name = "Tom";

 

// Получаем значение свойства и присваиваем его переменной - срабатывает блок Get

string personName = p.Name;

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

class Person

{

private int age;

 

public int Age

{

   set

   {

       if (value < 18)

       {

           Console.WriteLine("Возраст должен быть больше 17");

       }

       else

       {

           age = value;

       }

   }

   get { return age; }

}

}

Блоки set и get не обязательно одновременно должны присутствовать в свойстве. Например, мы можем закрыть свойство от установки, чтобы только можно было получать значение. Для этого опускаем блок set. И, наоборот, можно удалить блок get, тогда можно будет только установить значение, но нельзя получить:

class Person

{

private string name;

           // свойство только для чтения

public string Name

{

   get

   {

       return name;

   }

}

 

private int age;

           // свойство только для записи

public int Age

{

   set

   {

       age = value;

   }

}

}

Мы можем применять модификаторы доступа не только ко всему свойству, но и к отдельным блокам - либо get, либо set. При этом если мы применяем модификатор к одному из блоков, то к другому мы уже не можем применить модификатор:

class Person

{

private string name;

 

public string Name

{

   get

   {

       return name;

   }

 

   private set

   {

       name = value;

   }

}

           public Person(string name, int age)

{

   Name = name;

   Age = age;

}

}

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

Person p = new Person("Tom", 24);

 

// Ошибка - set объявлен с модификатором private

//p.Name = "John";

 

Console.WriteLine(p.Name);

Инкапсуляция

Выше мы посмотрели, что через свойства устанавливается доступ к приватным переменным класса. Подобное сокрытие состояния класса от вмешательства извне представляет механизм инкапсуляции, который представляет одну из ключевых концепций объектно-ориентированного программирования. Применение модификаторов доступа типа private защищает переменную от внешнего доступа. Для управления доступом во многих языках программирования используются специальные методы, геттеры и сеттеры. В C# их роль, как правило, выполняют свойства.

Например, есть некоторый класс Account, в котором определено поле sum, представляющее сумму:

class Account

{

           public int sum;

}

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

class Account

{

           private int sum;

           public int Sum

           {

                          get {return sum;}

                          set

                          {

                                          if (value > 0)

       {

           sum=value;

       }

                          }

           }

}

Автоматические свойства

Свойства управляют доступом к полям класса. Однако что, если у нас с десяток и более полей, то определять каждое поле и писать для него однотипное свойство было бы утомительно. Поэтому в фреймворк.NET были добавлены автоматические свойства. Они имеют сокращенное объявление:

class Person

{

public string Name { get; set; }

public int Age { get; set; }

                              

           public Person(string name, int age)

{

   Name = name;

   Age = age;

}

}

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

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


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: