C# и .NET Framework
Темы занятия
Свойства
Базовый синтаксис свойства
Пример свойства – 1
Работа со свойством
Пример свойства – 2
Трансляция свойств
Модификаторы доступа для get и set
Модификаторы доступа для get и set
Read-only и write-only свойства
Read-only свойства
Автосвойства – мотив возникновения
Автосвойства
Особенности автосвойств
Особенности автосвойств – пример
Свойство vs метод – best practices
Индексаторы
Синтаксис объявления индексатора
Пример простого индексатора
Использование индексатора
Примеры использования индексатора
Индексаторы – некоторые нюансы
Примеры (странных) индексаторов
Примеры (странных) индексаторов
Экземплярные конструкторы
Синтаксис конструктора
Пример класса с конструктором
Использование конструктора
Экземплярные конструкторы
Класс с двумя конструкторами
Конструктор по умолчанию
Инициализация объекта
Инициализация через индексатор
100.84K
Category: programmingprogramming

C# и .NET Framework. Свойства. Индексаторы. Экземплярные конструкторы. Инициализация объектов

1. C# и .NET Framework

ЗАНЯТИЕ 5

2. Темы занятия

Свойства
Индексаторы
Экземплярные конструкторы
Инициализация объектов

3. Свойства

Согласно принципу инкапсуляции, поля класса должны
быть закрытыми. Для обслуживания поля используется
либо пара открытых методов, либо свойство (property).
При работе с объектом свойство выглядит как поле, но
по сути состоит из двух (реже – одного) блоков кода,
обеспечивающих защищённый доступ к полю.

4. Базовый синтаксис свойства

модификаторы тип-свойства имя-свойства
{
get { операторы }
set { операторы }
}
Часть get (акцессор) работает как функция и отвечает за
возвращаемое свойством значение.
Часть set (мутатор) вызывается при записи значения
в свойство. Записываемое значение доступно в части set
через неявный параметр со специальным именем value.

5. Пример свойства – 1

public class Person
{
private int _age;
public int Age
{
get { return _age; }
set
{
_age = value > 0 ? value : 0;
}
}
}

6. Работа со свойством

var p = new Person();
p.Age = 18;
var x = p.Age;
// вызывается set-часть свойства
// вызывается get-часть

7. Пример свойства – 2

public class Test
{
// обычно свойство работает с полем,
// но это совершенно не обязательно!
public int Property
{
get { return 42; }
set { Console.WriteLine(value); }
}
}

8. Трансляция свойств

Свойства транслируются при компиляции в методы.
В код класса добавляются методы с именами get_Name()
и set_Name(), где Name – это имя свойства.
Кстати, для акцессора и мутатора можно использовать
стрелочный синтаксис => (начиная с C# 7).
*) Информация о свойстве сохраняется в метаданных

9. Модификаторы доступа для get и set

В C# разрешено при описании свойства указывать
модификаторы доступа для части get или части set.
Надо соблюдать два правила:
1. Модификатор может быть только у одной из частей.
2. Модификатор должен понижать видимость части по
сравнению с видимостью всего свойства.

10. Модификаторы доступа для get и set

public class Person
{
private int _age;
public int Age
{
get => _age;
internal set => _age = value > 0 ? value : 0;
}
}

11. Read-only и write-only свойства

Для свойства можно не указывать акцессор или мутатор:
public class Person
{
private int _age;
public bool IsAdult
{
get { return _age >= 18; }
}
}

12. Read-only свойства

Read-only свойство можно записать максимально
компактно при помощи стрелочного синтаксиса (C# 6):
public class Person
{
private int _age;
public bool IsAdult => _age >= 18;
}

13. Автосвойства – мотив возникновения

Часто свойство содержит простой код доступа к полю:
public class Person
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
}

14. Автосвойства

Для упрощения создания таких простых свойствобёрток, C# предлагает автосвойства (auto properties):
public class Person
{
public string Name { get; set; }
}
При объявлении автосвойства компилятор сам
добавляет в класс закрытое поле (со специальным
именем) и простой код доступа к этому полю.

15. Особенности автосвойств

1. Автосвойству можно дать начальное значение (по сути
это начальное значение для соответствующего поля).
2. Часть set при объявлении автосвойства можно не
указывать (связанное поле будет readonly, а свойство
можно инициализировать либо при объявлении, либо в
конструкторе класса).
*) Эти особенности работают, начиная с C# 6.

16. Особенности автосвойств – пример

public class Person
{
public string Name { get; }
public int Age { get; set; } = 18;
// это конструктор класса
public Person(string name)
{
Name = name;
}
}

17. Свойство vs метод – best practices

1. Чтение свойства два раза подряд должно возвращать
одинаковый результат (идемпотентность).
2. Работа со свойством как правило означает работу с
одним полем и не имеет побочных эффектов.
3. Медленная операция – это метод.
4. Свойство не возвращает массив.
5. Преобразователь информации объекта – это метод.

18. Индексаторы

Объект может инкапсулировать упорядоченный набор
значений. В этом случае доступ к элементам набора
естественно организовать не с помощью свойств, а при
помощи индекса (как это делается в массивах).
Для реализации такого поведения служит особая
разновидность свойств – индексаторы.

19. Синтаксис объявления индексатора

[модификаторы] тип this[параметры] { get-и-set-части }
Параметры индексатора задают типы и имена
индексов для доступа к данным. Параметры могут быть
описаны как параметры-значения (возможно, с
начальными значениями) или как список params.
Для акцессора и мутатора индексатора можно
использовать стрелочный синтаксис (начиная с C# 7).

20. Пример простого индексатора

public class Student
{
private readonly int[] _marks = new int[5];
public int this[int i]
{
get => _marks[i];
set => _marks[i] = value;
}
}

21. Использование индексатора

При использовании индексатора указывается ссылка на
объект и сразу после имени ссылки – значение индекса
(индексов) в квадратных скобках.
Допустимы именованные индексы (по аналогии с
именованными аргументами метода).
*) Если нужно обратиться к индексатору в пределах
класса, применяют синтаксис this[значение-индексов].

22. Примеры использования индексатора

var student = new Student();
student[1] = 8;
student[i:3] = 4;
// именованный индекс
for (var i = 0; i < 5; i++)
{
Console.WriteLine(student[i]);
}

23. Индексаторы – некоторые нюансы

Обычно индексаторы работают с полями-массивами
или полями-списками, но это не обязательно.
Допустимы read-only и write-only индексаторы.
Типы индексов у индексатора могут быть любыми.
Индексатор транслируется в методы get_Item() и
set_Item().
Класс может иметь несколько перегруженных
индексаторов.

24. Примеры (странных) индексаторов

public class WeirdIndexers
{
public int this[params int[] data]
{
get => data != null ? data.Length : 0;
set {}
}
public bool this[double x, double y] => x > y;
}

25. Примеры (странных) индексаторов

var
var
var
var
obj
a =
b =
c =
= new WeirdIndexers();
obj[3.5, 1.2]; // второй индексатор, a = true
obj[1, 3, 5];
// первый индексатор, b = 3;
obj[null];
// первый индексатор, c = 0;

26. Экземплярные конструкторы

Экземплярный конструктор (далее – конструктор)
служит для создания и инициализации объекта.
Выполнение конструктора начинается с размещения
объекта в динамической памяти (куче) и обнуления
полей объекта. Далее для полей устанавливаются
заданные начальные значения (если они есть). Потом
выполняется тело конструктора (если оно не пустое).

27. Синтаксис конструктора

Синтаксис конструктора похож на синтаксис метода.
Имя конструктора всегда совпадает с именем класса, а
любое указание на тип возвращаемого значения
отсутствует (нет даже void).
Допустимы модификаторы видимости.
Тело конструктора можно описать, используя
стрелочный синтаксис.

28. Пример класса с конструктором

public class Person
{
public int Age { get; }
public string Name { get; }
public Person(int age, string name)
{
Age = age;
Name = name;
}
}

29. Использование конструктора

// использование конструктора - операция new
var john = new Person(18, "John");
var mary = new Person(18, "Mary");
// вызвать конструктор как обычный метод нельзя!
john.Person(18, "John");
john = Person.Person(18, "John");

30. Экземплярные конструкторы

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

31. Класс с двумя конструкторами

public class Person
{
public string Name { get; }
public Person(string name) => Name = name;
public Person() : this("No name")
{
Console.Write(".ctor call");
}
}

32. Конструктор по умолчанию

Если программист не описал в классе собственный
конструктор, компилятор автоматически создаёт в
классе конструктор по умолчанию. Это publicконструктор без параметров и с пустым телом.
Внимание: при наличии любого пользовательского
экземплярного конструктора конструктор по умолчанию
уже не создаётся.

33. Инициализация объекта

Часто работа с объектом начинается с вызова
конструктора и установки public-элементов объекта:
var obj = new SomeClass();
obj.Prop1 = 1;
obj.Prop2 = "str";
Для таких действий допустим компактный синтаксис:
var obj = new SomeClass {Prop1 = 1, Prop2 = "str"};

34. Инициализация через индексатор

Если в классе есть индексатор, его можно использовать
для установки элементов объекта:
// класс Student описывали в примере индексатора
var student = new Student {[3] = 10, [1] = 7};
// стандартный класс-словарь
var cars = new Dictionary<int, string> {
[1] = "Ford", [2] = "Opel"};
English     Русский Rules