При создании классов всегда рекомендуется поля делать закрытыми (private
), что приводит к тому, что напрямую обращаться к ним вне класса становится невозможным. Причиной же почему существует такая рекомендация стали следующие ситуации:
-
пользователь, использующий данный класс может пытаться присваивать полям недопустимые для них значения, которые, например, приводят к неправильности работы всех внутренних методов. Конечно же можно писать различные проверки в коде перед присвоением, но эти проверки понадобятся во всех местах кода, и если в дальнейшем нужно будет добавить дополнительную проверку придётся просматривать полностью весь код, что наверняка покажется очень неудобным?
-
разработчики класса, когда создавали класс, подразумевали, что для некоторых полей запись должна быть запрещена, а для некоторых наоборот, должно быть запрещено чтение значения поля, а запись разрешена, но тут возникает проблема: мы не можем ограничить доступ к открытым полям, они всегда разрешают как запись, так и считывание. Использование проверок не спасёт в этом случае, а объявления полей константами (например,
public const double pi = 3.14d;
) не всегда будет подходить, ведь значения в поле, возможно, нужно изменять при работе определённых методов.
Примечание: константы в классах создаются точно так же, как и обычные константы в методах, и работа с ними ничем не отличается (разве-что только возможностью применения к ним модификаторов доступа).
Тогда возникает вопрос, как организовать безопасное считывание и запись в поле класса? Многие немного подумав, дойдут к выводу, что мы можем создать отдельные методы, которые и будут отвечать за работу с полями. Соответственно для каждого поля можно создать два вот-таких метода:
string name = null;
public void SetField(string value) // Метод-мутатор - mutator (setter)
{
// различные проверки
name = value;
}
publicstringGetField() // Метод-аксессор - accessor (getter)
{
// различные условия
return name;
}
Тип параметра метода отвечающего за запись отвечает типу полю, с которым он работает, а сам же метод в качестве результата своей работы ничего не возвращает (возвращает void
). Метод же отвечающий за считывание ничего не принимает, а возвращает значение, записанное в поле.
Методы, отвечающие за запись, зачастую называют методами-мутаторами - mutator (setter), а за считывание - методами-аксессорами - accessor (getter).
Теперь в дальнейшем нам ненужно будет дописывать различные проверки в коде перед присвоением/взятием значения полю, а достаточно будет поместить их в методы доступа. Но многие уже привыкли записывать значения в поля через оператор присвоения, а не через вызов метода, да и для каждого поля в классе придумывать название методов иногда может быть неудобно, поэтому запись этих методов было решено сократить до следующей формы:
private string name;
public string Field
{
set // void SetField(string value) - Метод-мутатор - mutator (setter)
{
// различные проверки
if (value != "fool")
{
name = value;
}
else
{
Console.WriteLine("try set fool");
}
}
get // string GetField() - Метод-аксессор - accessor (getter)
{
if (name == null) // проверки
return "name == null";
else
return name;
}
}
Таким образом:
- тип возвращаемого значения метода-аксессора и тип параметра метода-мутатора был указан в самом начале (
public string Field
) + имя параметра в методе-мутаторе всегда будетvalue
, поэтому к нему всегда можно будет обратиться. - названия методов были заменены двум ключевыми словами
set
иget
соответственно. - кроме этого это позволило работать с полем name как и прежде через присвоение (без вызова методов), но вместо обращения к name теперь нужно будет обращаться к
Field
.
Также конструкция, приведённая выше является свойством из чего следует, что «Свойство» — это:
- способ доступа к внутреннему состоянию объекта, имитирующий переменную некоторого типа;
- это конструкция языка C#, которая заменяет собой использование обычных методов доступа.
Работа со свойством экземпляра напоминает работу с полями экземпляра.
Свойство состоит из имени, типа и тела. В теле задаются методы доступа, через использование ключевых слов set
и get
.
Метод set
автоматически срабатывает тогда, когда свойству пытаются присвоить значение. Это значение представлено ключевым словом value
.
Метод get
автоматически срабатывает тогда, когда мы пытаемся получить значение.
Зачастую в качестве названия свойства берут название поля с которым оно работает, но первую букву пишут в верхнем регистре.
Если же посмотреть на свойство (не имеющее дополнительных проверок) через .NetReflector, то будет видно следующее:
Это говорит о том, что все свойства на самом деле являются методами.
Примечание: свойство необязательно должно быть связанно именно с полем, главное, что бы методы доступа работали правильно (соблюдены все требования к написанию метода)!