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

Содержание

Слайд 2

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

Темы занятия

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

Слайд 3

Свойства Согласно принципу инкапсуляции, поля класса должны быть закрытыми. Для обслуживания

Свойства

Согласно принципу инкапсуляции, поля класса должны быть закрытыми. Для обслуживания поля

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

Базовый синтаксис свойства модификаторы тип-свойства имя-свойства { get { операторы }

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

модификаторы тип-свойства имя-свойства
{
get { операторы }
set {

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

Пример свойства – 1 public class Person { private int _age;

Пример свойства – 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 p = new Person();
p.Age = 18; // вызывается

set-часть свойства
var x = p.Age; // вызывается get-часть
Слайд 7

Пример свойства – 2 public class Test { // обычно свойство

Пример свойства – 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

В C# разрешено при описании свойства

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

Модификаторы доступа для get и set public class Person { private

Модификаторы доступа для 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 свойства Для свойства можно не указывать акцессор или

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

Для свойства можно не указывать акцессор или мутатор:
public

class Person
{
private int _age;
public bool IsAdult
{
get { return _age >= 18; }
}
}
Слайд 12

Read-only свойства Read-only свойство можно записать максимально компактно при помощи стрелочного

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

Автосвойства

Для упрощения создания таких простых свойств-обёрток, C# предлагает автосвойства (auto properties):
public

class Person
{
public string Name { get; set; }
}
При объявлении автосвойства компилятор сам добавляет в класс закрытое поле (со специальным именем) и простой код доступа к этому полю.
Слайд 15

Особенности автосвойств 1. Автосвойству можно дать начальное значение (по сути это

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

1. Автосвойству можно дать начальное значение (по сути это начальное

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

Особенности автосвойств – пример public class Person { public string Name

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

public class Person
{
public string Name { get;

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

Свойство vs метод – best practices Чтение свойства два раза подряд

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

Чтение свойства два раза подряд должно

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

Индексаторы Объект может инкапсулировать упорядоченный набор значений. В этом случае доступ

Индексаторы

Объект может инкапсулировать упорядоченный набор значений. В этом случае доступ к

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

Синтаксис объявления индексатора [модификаторы] тип this[параметры] { get-и-set-части } Параметры индексатора

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

[модификаторы] тип this[параметры] { get-и-set-части }
Параметры индексатора задают

типы и имена индексов для доступа к данным. Параметры могут быть описаны как параметры-значения (возможно, с начальными значениями) или как список params.
Для акцессора и мутатора индексатора можно использовать стрелочный синтаксис (начиная с C# 7).
Слайд 20

Пример простого индексатора public class Student { private readonly int[] _marks

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

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;

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

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[]

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

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 obj = new WeirdIndexers(); var a =

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

var obj = new WeirdIndexers();
var a = obj[3.5, 1.2];

// второй индексатор, a = true
var b = obj[1, 3, 5]; // первый индексатор, b = 3;
var c = obj[null]; // первый индексатор, c = 0;
Слайд 26

Экземплярные конструкторы Экземплярный конструктор (далее – конструктор) служит для создания и

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

Экземплярный конструктор (далее – конструктор) служит для создания и инициализации

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

Синтаксис конструктора Синтаксис конструктора похож на синтаксис метода. Имя конструктора всегда

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

Синтаксис конструктора похож на синтаксис метода.
Имя конструктора всегда

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

Пример класса с конструктором public class Person { public int Age

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

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
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

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

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"};