Специальные методы доступа в С # .
Свойства
Кроме обычных методов в языке C# предусмотрены специальные методы доступа, которые называют свойства . Они обеспечивают простой доступ к полям класса, узнать их значение или выполнить их установку.
Стандартное описание свойства имеет следующий синтаксис:
[атрибуты] [спецификаторы] тип имя_свойства{ [get код_доступа] [set код_доступа]}
Значения спецификаторов для свойств и методов аналогичны. Чаще всего свойства объявляются как открытые (со спецификатором public ).
Стандартное определение свойства содержит блоки get и set. В блоке get мы возвращаем значение поля, а в блоке set устанавливаем.
class Person
{
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
}
Параметр value представляет передаваемое значение.
Здесь поле name закрытое и свойство Name общедоступное. Хотя они имеют практически одинаковое название за исключением регистра, но названия у них могут быть произвольные и не обязательно должны совпадать.
Через это свойство мы можем управлять доступом к переменной name.
Можно использовать данное свойство следующим образом:
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
{
Console.WriteLine("Возраст должен быть больше 17");
}
else
{
age = value;
}
}
get { return age; }
}
}
Блоки set и get не обязательно одновременно должны присутствовать в свойстве. Если свойство определяют только блок get, то такое свойство доступно только для чтения - мы можем получить его значение, но не установить.
И, наоборот, если свойство имеет только блок set, тогда это свойство доступно только для записи - можно только установить значение, но нельзя получить:
- 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);
При использовании модификаторов в свойствах следует учитывать ряд ограничений:
- Модификатор для блока set или get можно установить, если свойство имеет оба блока (и set, и get).
- Только один блок set или get может иметь модификатор доступа, но не оба сразу.
- Модификатор доступа блока set или get должен быть более ограничивающим, чем модификатор доступа свойства. Например, если свойство имеет модификатор public, то блок set/get может иметь только модификаторы protected internal, internal, protected, private.
Инкапсуляция
Через свойства можно установить доступ к приватным переменным класса. Подобное сокрытие состояния класса от вмешательства извне представляет механизм инкапсуляции .
Применение модификаторов доступа типа private защищает переменную от внешнего доступа. Для управления доступом во многих языках программирования используются специальные методы, геттеры и сеттеры. В C# их роль выполняют свойства.
Например, есть некоторый класс Account , в котором определено поле sum, представляющее сумму:
class Account
{
public int sum;
}
Так как переменная sum является публичной, то в любом месте программы можно получить к ней доступ и изменить ее, в том числе установить какое-либо недопустимое значение, например, отрицательное. А это не является желательным. Поэтому применяется инкапсуляция для ограничения доступа к переменной sum и сокрытию ее внутри класса:
0) { sum=value; } } } } " width="640"
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;
}
}
В примере также создаются поля для свойств, только их создает не программист в коде, а компилятор автоматически генерирует при компиляции.
В чем преимущество автосвойств, если по сути они просто обращаются к автоматически создаваемой переменной, почему бы напрямую не обратиться к переменной без автосвойств? Дело в том, что в любой момент времени при необходимости мы можем развернуть автосвойство в обычное свойство, добавить в него какую-то определенную логику.
Стоит учитывать, что нельзя создать автоматическое свойство только для записи, как в случае со стандартными свойствами.
Автосвойствам можно присвоить значения по умолчанию (инициализация автосвойств):
class Person
{
public string Name { get; set; } = "Tom";
public int Age { get; set; } = 23;
}
class Program
{
static void Main(string[] args)
{
Person person = new Person();
Console.WriteLine(person.Name); // Tom
Console.WriteLine(person.Age); // 23
Console.Read();
}
}
Если не укажем для объекта Person значения свойств Name и Age, то будут действовать значения по умолчанию.
Автосвойства также могут иметь модификаторы доступа:
class Person
{
public string Name { private set; get;}
public Person(string n)
{
Name = n;
}
}
Можно убрать блок set и сделать автосвойство доступным только для чтения. В этом случае для хранения значения этого свойства для него неявно будет создаваться поле с модификатором readonly, поэтому следует учитывать, что подобные get-свойства можно установить либо из конструктора класса, как в примере выше, либо при инициализации свойства:
class Person
{
public string Name { get;} = "Tom"
}
name; // эквивалентно public string Name { get { return name; } } } " width="640"
Сокращенная запись свойств
Как и методы, можно сокращать свойства. Например:
class Person
{
private string name;
public string Name = name;
// эквивалентно public string Name { get { return name; } }
}