C классы get set – Вэб-шпаргалка для интернет предпринимателей!

Дескрипторы свойств объекта в JavaScript. Геттер (get) и сеттер (set): особенности использования.

Свойства

Последнее обновление: 03.10.2019

Кроме обычных методов в языке 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” и есть передаваемое в свойство valuep.Name = “Tom”;// Получаем значение свойства и присваиваем его переменной – срабатывает блок Getstring personName = p.Name;

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

class Person{ private int age; public int Age { set { if (value < 18) { Console.WriteLine(“Возраст должен быть больше 17”); } else { age = value; } } get { return age; } }}

Если бы переменная 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) { Name = name; }}

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

Person p = new Person(“Tom”);// Ошибка – 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

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

Свойства управляют доступом к полям класса. Однако что, если у нас с десяток и более полей, то определять каждое поле и писать для него однотипное свойство было бы утомительно. Поэтому в фреймворк .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”}

Сокращенная запись свойств

Как и методы, мы можем сокращать свойства. Например:

class Person{ private string name; // эквивалентно public string Name { get { return name; } } public string Name => name;}

НазадСодержаниеВперед

Метод доступа getThe get Accessor

Тело метода доступа get похоже на тело метода.The body of the get accessor resembles that of a method. Оно должно возвращать значение заданного типа свойства.It must return a value of the property type. Выполнение метода доступа get эквивалентно считыванию значения поля.The execution of the get accessor is equivalent to reading the value of the field. Например, если включена оптимизация и метод доступа get возвращает частную переменную, вызов метода доступа get определяется компилятором как встроенный, что позволяет исключить затраты ресурсов на вызов метода.For example, when you are returning the private variable from the get accessor and optimizations are enabled, the call to the get accessor method is inlined by the compiler so there is no method-call overhead. Тем не менее виртуальный метод доступа get не может определяться как встроенный, поскольку во время компиляции компилятору не известно, как метод может быть фактически вызван во время выполнения.However, a virtual get accessor method cannot be inlined because the compiler does not know at compile-time which method may actually be called at run time. Ниже показан метод доступа get, возвращающий значение частного поля _name:The following is a get accessor that returns the value of a private field _name:

class Person{ private string _name; // the name field public string Name => _name; // the Name property}

При ссылке на свойство (кроме случаев, когда свойство является целью присваивания) вызывается метод доступа get, который считывает значение свойства.When you reference the property, except as the target of an assignment, the get accessor is invoked to read the value of the property. Пример:For example:

Person person = new Person();//…System.Console.Write(person.Name); // the get accessor is invoked here

Метод доступа get должен завершаться инструкцией return или throw, при этом управление не может передаваться из тела метода доступа.The get accessor must end in a return or throw statement, and control cannot flow off the accessor body.

Изменение состояния объекта с помощью метода доступа get считается ошибочным стилем программирования.It is a bad programming style to change the state of the object by using the get accessor. Например, побочным эффектом следующего метода доступа является изменение состояния объекта каждый раз при доступе к полю _number.For example, the following accessor produces the side effect of changing the state of the object every time that the _number field is accessed.

private int _number;public int Number => _number++; // Don’t do this

Метод доступа get можно использовать для возврата значения поля напрямую или после вычисления.The get accessor can be used to return the field value or to compute it and return it. Пример:For example:

class Employee{ private string _name; public string Name => _name != null ? _name : “NA”;}

Если в предыдущем фрагменте кода свойству Name не присвоено значение, будет возвращено значение NA.In the previous code segment, if you do not assign a value to the Name property, it will return the value NA.

Зачем делать переменные-члены класса закрытыми?

В качестве ответа, воспользуемся аналогией. В современной жизни мы имеем доступ ко многим электронным устройствам. К телевизору есть пульт дистанционного управления, с помощью которого можно включать/выключать телевизор. Управление автомобилем позволяет в разы быстрее передвигаться между двумя точками. С помощью фотоаппарата можно делать снимки.

Все эти 3 вещи используют общий шаблон: они предоставляют вам простой интерфейс (кнопка, руль и т.д.) для выполнения определенного действия. Однако, то, как эти устройства фактически работают, скрыто от вас (как от пользователей). Для нажатия кнопки на пульте дистанционного управления вам не нужно знать, что выполняется «под капотом» пульта для взаимодействия с телевизором. Когда вы нажимаете на педаль газа в своем автомобиле, вам не нужно знать о том, как двигатель внутреннего сгорания приводит в движение колеса. Когда вы делаете снимок, вам не нужно знать, как датчики собирают свет в пиксельное изображение.

Такое разделение интерфейса и реализации чрезвычайно полезно, поскольку оно позволяет использовать объекты, без необходимости понимания их реализации. Это значительно снижает сложность использования этих устройств и значительно увеличивает их количество (устройства с которыми можно взаимодействовать).

По аналогичным причинам разделение реализации и интерфейса полезно и в программировании.

Свойства C#

Свойства C# представляют собой отдельную структуру данных. В теме «Объекты на C#» был приведен пример кода:

/// <summary>/// Класс “Персонаж”./// </summary>class Character{ /// <summary> /// Имя персонажа. /// </summary> public string Name; /// <summary> /// Пол. /// </summary> public string Gender; /// <summary> /// Сила. /// </summary> public double Strength; /// <summary> /// Ловкость. /// </summary> public double Agility; /// <summary> /// Объем здоровья. /// </summary> public double Health;}

Для класса «Персонаж» был объявлен набор переменных. На самом деле, подобный код считается примером очень плохого стиля программирования, потому как согласно правилам хорошего кода переменные обязаны быть закрытыми для изменения извне. Открытыми могут быть только свойства.

Функции доступа (геттеры и сеттеры)

В зависимости от класса, может быть уместным (в контексте того, что делает класс) иметь возможность получать/устанавливать значения закрытым переменным-членам класса.

Функция доступа — это короткая открытая функция, задачей которой является получение или изменение значения закрытой переменной-члена класса. Например:

classMyString

{

private:

    char*m_string;// динамически выделяем строку

    intm_length;// используем переменную для отслеживания длины строки

public:

    intgetLength(){returnm_length;}// функция доступа для получения значения m_length

};

Здесь getLength() является функцией доступа, которая просто возвращает значение m_length.

Функции доступа обычно бывают двух типов:

   геттеры — это функции, которые возвращают значения закрытых переменных-членов класса;

   сеттеры — это функции, которые позволяют присваивать значения закрытым переменным-членам класса.

Вот пример класса, который использует геттеры и сеттеры для всех своих закрытых переменных-членов:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

classDate

{

private:

    intm_day;

    intm_month;

    intm_year;

public:

    intgetDay(){returnm_day;}// геттер для day

    voidsetDay(intday){m_day=day;}// сеттер для day

    intgetMonth(){returnm_month;}// геттер для month

    voidsetMonth(intmonth){m_month=month;}// сеттер для month

    intgetYear(){returnm_year;}// геттер для year

    voidsetYear(intyear){m_year=year;}// сеттер для year

};

В этом классе нет никаких проблем с тем, чтобы пользователь мог напрямую получать или присваивать значения закрытым переменным-членам этого класса, так как есть полный набор геттеров и сеттеров. В примере с классом MyString для переменной m_length не было предоставлено сеттера, так как не было необходимости в том, чтобы пользователь мог напрямую устанавливать длину.

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

Хотя иногда вы можете увидеть, что геттер возвращает неконстантную ссылку на переменную-член — этого следует избегать, так как в таком случае нарушается инкапсуляция, позволяя caller-у изменять внутреннее состояние класса вне этого же класса. Лучше, чтобы ваши геттеры использовали тип возврата по значению или по константной ссылке.

Правило: Геттеры должны использовать тип возврата по значению или по константной ссылке. Не используйте для геттеров тип возврата по неконстантной ссылке.

См. такжеSee also

  • Руководство по программированию на C#C# Programming Guide
  • СвойстваProperties
  • Свойства интерфейсаInterface Properties
  • Автоматически реализуемые свойстваAuto-Implemented Properties

Значение свойства по умолчанию в C#

Иногда бывает необходимо инициализировать значение свойства значением, отличным, от значения по умолчанию для типа данных. Например, наше новое свойство Name имеет тип данных string (строка) и по умолчанию будет инициализировано как null, так как строки относятся к ссылочным типам данных. Если мы хотим, чтобы сразу при создании объекта наше свойство получило некоторое значение по умолчанию, то мы можем сделать это следующим образом:

class Building{ public string Name { get; set; } = “Неизвестное здание”;}

То есть сразу после закрывающей скобки } для свойства ставится равно и пишется значение свойства по умолчанию.

Рейтинг
( 1 оценка, среднее 5 из 5 )
Загрузка ...