Similar presentations:
Лекция_8_2025
1. АЛГОРИТМИЗАЦИЯ И ПРОГРАММИРОВАНИЕ
12. ДЕКОНСТРУКТОРЫ
Деконструкторы позволяют выполнить декомпозицию объекта на отдельныечасти.
Например, пусть есть следующий класс Person:
class Person
{
string name;
int age;
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
public void Deconstruct(out string personName, out int personAge)
{
personName = name;
personAge = age;
}
}
2
3. ДЕКОНСТРУКТОРЫ
В этом случае можно выполнить декомпозицию объекта Person следующимобразом:
Person person = new Person(“Ivan", 20);
(string name, int age) = person;
Console.WriteLine(name);
Console.WriteLine(age);
Можно написать:
Person person = new Person(" Ivan", 20);
string name; int age;
person.Deconstruct(out name, out age);
При получении значений из декоструктора необходимо предоставить столько
переменных, сколько деконструктор возвращает значений. Однако бывает,
что не все эти значения нужны. И вместо возвращаемых значений можно
использовать прочерк _. Например, надо получить только возраст
пользователя:
Person person = new Person(" Ivan", 20);
(_, int age) = person;
Console.WriteLine(age);
3
4. ДЕКОНСТРУКТОРЫ
using System;class Person
{
string name;
int age;
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
public void Deconstruct(out string personName, out int personAge)
{
personName = name;
personAge = age;
}
}
class HelloWorld
{
static void Main()
{
Person person = new Person("Ivan", 20);
(string name, int age) = person;
Console.WriteLine(name);
Console.WriteLine(age);
}
}
4
5. ДЕКОНСТРУКТОРЫ
using System;class Person
{
string name;
int age;
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
public void Deconstruct(out string personName, out int personAge)
{
personName = name;
personAge = age;
}
}
class HelloWorld
{
static void Main()
{
Person person = new Person(" Ivan", 20);
string name; int age;
person.Deconstruct(out name, out age);
Console.WriteLine(name);
Console.WriteLine(age);
}
}
5
6. ДЕКОНСТРУКТОРЫ
using System;class Person
{
string name;
int age;
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
public void Deconstruct(out string personName, out int personAge)
{
personName = name;
personAge = age;
}
}
class HelloWorld
{
static void Main()
{
Person person = new Person(" Ivan", 20);
(_, int age) = person;
Console.WriteLine(age));
}
}
6
7. КЛАССЫ
Члены класса могут иметь атрибут static. Необходимость его введения былавызвана теми обстоятельствами, что создаваемые из класса объекты
должны были иметь по некоторым полям, например, общие значения или
обладать общими методами. Это удобно, т. к. нет необходимости иметь в
каждом объекте один и тот же метод, достаточно получить его на уровне
класса, из которого создается этот метод.
Например, создается класс по персоналу предприятия. Каждый объект,
получаемый из этого класса, - это отдельный работник со всеми своими
характеристиками. У всех работников могут быть одинаковые, например,
некоторые процентные надбавки. Такие поля следует делать статическими,
и они будут во всех объектах одинаковы. Достаточно изменить их на уровне
класса, как изменения отразятся во всех объектах. Или методы некоторых
расчетов: изменился алгоритм, метод изменяется на уровне класса, и для
всех сотрудников обновился метод расчета.
Статические члены класса могут оперировать только другими статическими
членами, в противном случае на этапе компиляции возникнет ошибка.
Для обращения к статическому члену обязательно надо указывать имя класса,
которому этот член принадлежит.
7
8. СТАТИЧЕСКИЙ КОНСТРУКТОР
При создании статических полей класса они распределяются по всемэкземплярам класса. Для них в памяти выделяется специальный участок,
который не сбрасывается, когда объект уничтожается.
Нестатические поля - это независимые копии полей для каждого объекта. И
они при ликвидации объекта уничтожаются вместе с ним, т. е. память от
них освобождается.
При создании класса создаются статические поля, которые получают
конкретные (статические) значения. Например,
static Rate=0.12;
Если значение статического поля определяется не в момент создания класса, а
в момент работы приложения, когда из приложения надо обратиться к базе
данных, чтобы взять оттуда, например, значение процентной ставки. И это
надо сделать до создания объекта. Поле процентной ставки имеет атрибут
static.
Для решения проблемы используется статический конструктор, который
выполняется всего один раз перед конструктором, создающим объекты.
Статический конструктор используется для инициализации любых статических
данных или для определенного действия, которое требуется выполнить
только один раз. Он вызывается автоматически перед созданием первого
экземпляра или когда идет первое обращение к статическому члену.
8
9. СТАТИЧЕСКИЙ КОНСТРУКТОР
ПРИМЕРclass SimpleClass
{
// Статическая переменная, которая должна быть
// инициализирована во время выполнения программы:
static long dt;
// Статический конструктор, который вызывается только
// один раз перед любым конструктором, создающим
// экземпляр класса, или при первой встрече переменной dt:
static SimpleClass()
{
dt = 20;
}
}
Исполняющая среда вызовет этот конструктор перед созданием экземпляра
класса SimpleClass и перед первым обращением к переменной dt.
static class MyClass {}
9
10. ССЫЛОЧНЫЕ ТИПЫ
В C# определение типа (класса, структуры или записи) похоже на схему,которая определяет, что может сделать тип. Объект является блоком
памяти, выделенной и настроенной в соответствии со схемой.
Ссылочные типы:
• Тип object
• Тип string
• Классы (class)
• Интерфейсы (interface)
• Делегаты (delegate)
Память делится на два типа: стек и куча (heap).
Стек представляет собой структуру данных, которая растет снизу вверх:
каждый новый добавляемый элемент помещается поверх
предыдущего. Время жизни переменных таких типов ограничено их
контекстом.
Физически стек - это некоторая область памяти в адресном
пространстве.
10
11. ССЫЛОЧНЫЕ ТИПЫ
Параметры и переменные метода, которые представляют типызначений, размещают свое значение в стеке.
Когда программа только запускается на выполнение, в конце блока
памяти, зарезервированного для стека устанавливается указатель
стека. При помещении данных в стек указатель переустанавливается
таким образом, что снова указывает на новое свободное место.
При вызове каждого отдельного метода в стеке будет выделяться
область памяти или фрейм стека, где будут храниться значения его
параметров и переменных.
В C# определение типа (класса, структуры или записи) похоже на схему,
которая определяет, что может сделать тип. Объект является блоком
памяти, выделенной и настроенной в соответствии со схемой.
Экземпляры классов
Так как классы являются ссылочными типами, в переменной объекта
класса хранится ссылка на адрес объекта в управляемой куче. Если
первой переменной присваивается Вторая переменная того же типа,
то обе переменные ссылаются на объект по этому адресу.
11
12. Классы. Инкапсуляция.
Капсула по латыни означает "коробочка", "ин" – предлог "В". Поэтомудословный перевод первого принципа ООП – "в коробочке".
Черный ящик, в котором прячутся все детали реализации проблемы, но
с помощью этого ящика программист может решить саму проблему,
не отвлекаясь на детали ее реализации.
Класс содержит (хранит) данные, причем таким образом, что к ним нет
прямого доступа извне. Есть доступ только с помощью методов,
хранящихся тоже в классе. Таким способом обеспечивается защита
данных от внешнего вмешательства.
В классе содержаться данные о состоянии объекта, который описан в
нем. К этим данным доступа нет, если им присвоить атрибут private.
Только через специальные методы, находящиеся там же, в классе
(методы с именами get (получить данное) и set (установить данное в
определенное значение)).
Когда задаются поля класса (а именно они определяют своими
значениями состояние в данный момент объекта класса), эти поля
должны задаваться с атрибутом private, чтобы к ним извне не было
доступа. В таком случае они доступны только для методов,
определенных в данном классе.
12
13. Классы. Инкапсуляция.
Общедоступными (имеющие атрибут public) данными могут бытьобщедоступные константы, другие поля, которые определены лишь
для чтения. Последние имеют специальный атрибут readonly.
Константы не всегда соответствуют всем требованиям ситуации с
реализацией алгоритма. Часто случается так, что переменную нужно
получить в результате расчетов, а потом сделать ее "только для
чтения".
В C# предусмотрен тип переменных readonly. Переменные поля
readonly имеют большую гибкость, чем const (атрибут, с которым
объявляется константа), потому что позволяют перед присваиванием
производить различные вычисления значения, которое должно быть
"только для чтения".
Правило использования таких полей говорит, что можно присваивать им
значение только в конструкторе (лишь конструктор инициализирует
поля, это его функция).
Одной из основных особенностей таких полей является то, что они могут
принадлежать и экземплярам класса, а не быть статическими, как
константы (при объявлении константы атрибут static запрещен, т. к.
по своей сути константа — уже сама по себе статический элемент).
13
14. Классы. Инкапсуляция.
Это позволяет получать различные значения полей "только для чтения"в разных экземплярах классов. Но если необходимо сделать поле
readonly статическим, то должны явно объявить его таковым, в
отличие от полей const.
ПРИМЕР
Пусть в некотором классе А имеется метод вычисления количества
поставщиков supp(). Объекты, получаемые из класса А, должны
работать какое-то время с одним количеством поставщиков, а через
некоторый промежуток - с другим количеством. То есть на
определенном отрезке времени поле "Количество поставщиков", NumSupp, должно быть как бы константой.
public class A
{
public static readonly uint NumSupp;
static A() // статический конструктор
{
NumSupp = supp (Data);
}
}
14 и
В данном примере объявляется переменная как статическая
используется в экземпляре класса при каждом запуске программы.
15. Классы. Инкапсуляция.
Функция supp(Data) вычислит количество поставщиков на данную дату,и с помощью конструктора поле NumSupp получит заданное
значение, с которым станут работать все экземпляры класса.
Управление приватными данными класса осуществляется двумя
методами с именами get и set.
Инкапсуляция с использованием методов get и set
ПРИМЕР
Построим класс Employee, моделирующий сотрудника некоторого
предприятия. В нем определяется поле "Имя сотрудника«, к которому
вне класса доступа нет. (private).
Вид объявления в классе будет private string empName; (имя строковое значение, т. е. данное типа string). Чтобы прочитать это
значение из класса, надо создать метод, который имел бы право
читать это данное и выдавал бы его значение. Начинаться он должен
с части Get (получить). То есть его имя будет, например, GetName().
Этот метод будет вызываться из исполняющей программы, а не в самом
классе. Поэтому он должен быть известен в исполняющей
программе, т. е. быть общедоступным, не спрятанным в классе.
Значит, его атрибут доступа - public.
15
16. Классы. Инкапсуляция.
Ондолжен возвращать имя сотрудника. Следовательно, тип
возвращаемого значения у метода будет string (как и тип имени
сотрудника).
Окончательно метод чтения поля empName будет выглядеть так:
public string GetName()
{
return empName;
}
Обращение к методу можно было бы записать:
string s = GetName();
Но при работе с классом предварительно надо создать из класса объект
по конкретному сотруднику (т. е. некоторой переменной emp
присвоить тип класса Employee).
Запись будет выглядеть следующим образом:
Employee emp = new Employee("Иванов И. И.", остальные аргументы
конструктора);
string s = emp.GetName();
16
17. Классы. Инкапсуляция.
Для изменения значений полей создается метод, который позволяетизменить поле из внешней программы - SetName() (установить
значение поля Name).
Как пример будет выполняться простое действие: проверяется
значение, которое присвоится полю, на его длину.
Пусть имя работника не должно превышать девяти символов. Эта
проверка будет определена в методе.
Метод должен иметь общедоступность, т. е. должен быть снабжен
атрибутом public. Возвращать по оператору return ничего не
требуется, поэтому метод имеет тип возвращаемого значения void.
На входе метод должен иметь параметр типа string, т. к. он должен
принимать некую строку текста, которой заменит значение поля в
классе. Таким образом, метод может иметь вид:
public void SetName(string Name)
{
if(Name.Length > 9)
WriteLine("Ошибка: длина имени больше 9 ");
else
17
empName = Name;
}
18. Классы. Инкапсуляция.
Предполагается, что метод находится в классе, поэтому для негопеременная empName доступна.
В итоге для задания одного поля класса Employee в соответствии с
принципом инкапсуляции получается программу
using System;
namespace appt
{
class Employee
{
private string empName; // поле
// Конструктор: должен иметь атрибут public,
// иначе его нельзя будет вызвать
// из основной программы
public Employee(string name)
{
empName=name;
}
18
19. Классы. Инкапсуляция.
// Методы класса:public string GetName()
{
return empName;
}
public int SetName(string Name)
{
if(Name.Length > 9)
{
Console.WriteLine("Ошибка: длина имени "+"больше 9, имя = {0}", Name);
return 0;
}
else
{
empName = Name;
return 1;
}}} // конец класса
19
20. Классы. Инкапсуляция.
class Program{
public static void Main()
{
// Создаем объект из класса:
Employee emp = new Employee("Иванов И.И.");
// Достается поле name из объекта (если бы поле имело атрибут static,
// можно было его достать прямо из класса):
string s=emp.GetName();
Console.WriteLine("Поле name = {0}",s);
Console.Write("Продолжить: <Enter> >");
// Изменяется значение поля name:
if(emp.SetName("Петров П.П.") == 0)
emp.SetName("Петров П."); // для примера
s=emp.GetName();
Console.WriteLine("Поле name = {0}",s);
Console.Write("Продолжить: <Enter> >");
Console.ReadKey(true);
20
}}}
21. Классы. Инкапсуляция.
Инкапсуляция с использованием свойствВ С# имеется другой, более удобный способ инкапсулирования данных
– это использование так называемых свойств.
Свойства – это упрощенное синтаксическое представление методов
доступа к полю.
Свойство – это специальное поле класса, содержащее программный
код доступа к внутренним переменным (полям) класса или
вычисления некоторого значения. Свойства обеспечивают удобный
доступ к внутренней переменной в классе.
Общая форма объявления свойства в классе
type PropName
{
get
{
// код для чтения внутреннего поля (переменной)
// ...
}
set
{
// код для записи значения во внутреннее поле (переменную)
// ...
}}
21
22. Классы. Инкапсуляция.
гдеtype – тип данных возвращаемый свойством;
PropName – имя свойства. По этому имени идет обращение к свойству;
get – аксессор, который используется для чтения значения из
внутреннего поля класса;
set – аксессор, используемый для записи значения во внутреннее поле
класса. Аксессор set получает неявный параметр value, содержащий
значение, которое присваивается свойству.
Если имя свойства встречается в правой части оператора присваивания
или в выражении тогда вызывается get.
Если имя свойства встречается в левой части оператора присваивания
тогда вызывается аксессор set.
22
23. Классы. Инкапсуляция.
Добавим к классу Employee еще одно поле: табельный номерработника.
using System;
namespace app_properties
{
class Employee
{
private string empName;
private int empID;
private float empPay;
// Конструктор с полями
public Employee(string Name, int ID, float Pay)
{
empName=Name;
empID=ID;
empPay=Pay;
}
23
24. Классы. Инкапсуляция.
// Конструктор со свойствами/*
Чтобы конструкторы различались, параметр Pay взят другого типа. Но
поле empPay объявлено типа float, поэтому понадобилось
принудительное приведение параметра Pay к типу float. this взят из-за
одинаковости имен параметров и свойств
*/
public Employee(string Name, int ID, double Pay)
{
this.Name=Name;
this.ID=ID;
this.Pay=(float)Pay;
}
// Так определяются свойства Name, ID, Pay:
public string Name
{
get { return empName; }
24
25. Классы. Инкапсуляция.
set{
if (value.Length > 9)
Console.WriteLine ("Ошибка: длина имени > 9. "+"Имя = {0}", value);
else
empName = value;
} // set
} // Name
public int ID
{
get { return empID; }
set { empID = value; }
} // ID
public float Pay
{
get {return empPay;}
set { empPay = value;}
}
} // Employee
25
26. Классы. Инкапсуляция.
class Program{
public static void Main()
{
Employee emp = new Employee("Иваормормропрнов", 411, 15000);
// Вывод полей объекта через вывод свойств:
Console.WriteLine("empName = {0}",emp.Name);
Console.WriteLine("empID = {0}",emp.ID);
Console.WriteLine("empPay = {0}",emp.Pay);
// emp.SetPay(emp.GetPay() + 1000); // Без свойств надо было бы так
делать
emp.Pay += 1000; // emp.Pay будет равно 16000
Console.WriteLine("empPay после добавления 1000 к свойству Pay =
{0}",emp.Pay);
// Создание объекта из конструктора с помощью задания свойств
Console.WriteLine("Создание объекта через свойства:");
Employee emp1 = new
Employee("Петроворпшооорторропроп",001,25000);
26
27. Классы. Инкапсуляция.
// Вывод полей объекта через вывод свойств:Console.WriteLine("empName = {0}",emp1.Name);
Console.WriteLine("empID = {0}",emp1.ID);
Console.WriteLine("empPay = {0}",emp1.Pay);
Console.Write("Press any key to continue... ");
Console.Read();
}
}
}
27
28. Классы. Инкапсуляция.
2829. Классы. Инкапсуляция.
Свойства имеют такие же имена, как и соответствующие поля, дляобработки которых создаются свойства.
Тип доступа к свойствам – public, т. к. это фактически методы, которые
станут вызываться вне данного класса, поэтому и должны быть
общедоступными. У свойства есть тело, ограниченное фигурными
скобками, в которое помещены два специальных метода управления
соответствующим свойству полем.
У методов заданные в среде исполнения имена get (получить значение
поля) и set (установить значение поля).
Метод get() возвращает значение поля, метод set() присваивает полю
значение переменной value, которое определяется в основной
программе, исполняющей метод set().
Тип value всегда совпадает с типом свойства. Свойства хороши не
только более короткой формой записи, но и также тем, что они могут
участвовать в операциях внутри класса.
29
30. Классы. Инкапсуляция.
ПРИМЕРДобавим поле private float empPay (зарплата), которому будет
соответствовать свойство, определенное как
public float Pay
{
get {return empPay;}
set { empPay = value;}
}
(компилятор потом преобразует эту короткую запись в обыкновенные
функции-методы), если потребуется увеличить зарплату на 1000, то
при отсутствии аппарата свойств надо было бы писать операторы:
Employee emp = new Employee("Иванов");
emp.SetPay(emp.GetPay() + 1000);
а с использованием свойства Pay можно записать
emp.Pay += 1000;
Вместо имени поля после точки надо поставить имя свойства.
30
31. Классы. Инкапсуляция.
В данном случае компилятором будет построено обращение к методуget(), который выведет на поле. А обращение к полю для вывода его
содержимого (обращались через метод GetИмяПоля()) будет таким:
emp.Pay.
С вводом понятия свойств имеется возможность в основных
программах, использующих классы, даже не догадываться, что
существуют какие-то методы get и set, хотя раньше в основной
программе надо было писать обращение к методам SetName(),
GetName() и т. п.
И еще одна возможность появилась после ввода понятия свойств: в
конструкторе теперь можно не писать присвоение параметров полям
класса, а сразу - свойствам.
31
32. Классы. Инкапсуляция.
Если раньше конструктор был представлен в виде:public Employee(string name)
{
empName=name;
}
то теперь можно писать в виде:
public Employee(string name)
{
Name=name;
}
где Name - это имя свойства, связанного с полем empName.
В конструкторе же можно задавать операторы, проверяющие на
достоверность вводимые данные
32
33. Классы. Инкапсуляция.
О доступности и статичности свойствКогда при определении свойства заданы оба метода get, set, то такое
свойство доступно как для чтения, так и для записи (модификации).
Если какой-то из методов не указать, то свойство станет либо
доступным только для чтения (присутствует только метод get), либо
только для записи (присутствует только метод set). Если поле класса
имеет атрибут static, то вполне естественно, что и свойство для
этого поля надо объявлять с таким же атрибутом.
Автоматические свойства
При определении свойства оно задается парой методов get-set, в телах
которых (в фигурных скобках) только простейшие операторы –
возврата и присвоения. В большинстве случаев описание get set
этим и ограничивается. Если в классе много свойств, то записывать
почти одно и то же содержимое в фигурных скобках увеличивает код
программы и восприятие программы.
Разработчики языка дали возможность отказаться от записи полей, а
потом на их основе – записи свойств, а ввели возможность сразу
определять свойства без описания полей и свойства писать
33
покороче.
34. Классы. Инкапсуляция.
private float empPay; // полеpublic float Pay // свойство
{
get { return empPay; }
set { empPay = value; }
}
Теперь поле не определяют, а пишут сразу вид свойства:
public float Pay {get; set;}
Компилятор, который автоматически создает свойство таким, каким ему
положено быть из этой синтаксической конструкции, и обеспечивает
работу программиста только со свойством. Таким образом
определенные свойства называют автоматическими.
34
35. Классы. Инициализация.
Инициализация объектаИнициализация объекта происходит через конструктор, в котором при
создании объекта задаются конкретные значения параметров.
Существует еще один способ инициализации, синтаксис которого –
список значений общедоступных полей и/или свойств (свойства по
определению общедоступны), заключенный в фигурные скобки.
Например, имеем класс р, описанный как
class p
{
// Свойства (автоматические)
public int x {get; set;}
public int y {get; set;}
// Конструкторы
public p()
{}
public p(int v1, int v2)
{
x=v1;
35
y=v2;
}}
36. Классы. Инициализация.
C помощью этих конструкторов можно создать объекты обычнымспособом:
p ob1=new p();
ob1.x=10;
ob1.y=20;
или
p ob2=new p(10,20);
А с помощью синтаксиса инициализации можно написать:
p ob=new p {x=10, y=20};
При таком синтаксисе конструктор класса - конструктор по умолчанию вызывается неявно. Но можно его вызывать и явно, записав
p ob=new p() {x=10, y=20};
При инициализации объекта таким образом можно вызывать не только
конструктор по умолчанию, но и любой другой определенный в классе.
Например, можно записать:
36
p ob2=new p(10,20) {x=30, y=40};
Свойства класса получат, естественно, последние значения (30, 40).
37. Классы. Инициализация.
Применение синтаксиса инициализации объектов более наглядно иудобно при большом количестве свойств, полей и конструкторов в
классе. В этом случае не надо думать, какой конструктор выбрать
для данного объекта: можно взять конструктор по умолчанию и в
фигурных скобках написать названия нужных свойств и/или полей и
присваиваемые им значения.
using System;
namespace app
{
class p
{
// Свойства (автоматические)
public int x {get; set;}
public int y {get; set;}
// Конструкторы
public p()
{
}
37
38. Классы. Инициализация.
public p(int v1, int v2){
x=v1; y=v2;
}}
class Program
{
public static void Main()
{
p ob1=new p(); ob1.x=10; ob1.y=20;
Console.WriteLine("Инициализация свойств через "+"конструктор по
умолчанию: x={0} y={1}",ob1.x, ob1.y);
p ob2=new p(10,20);
Console.WriteLine("Инициализация свойств через " +"двухаргументный
конструктор: x={0} y={1}",ob2.x, ob2.y);
p ob=new p {x=10, y=20};
Console.WriteLine("Инициализация свойств через "+"синтаксис
инициализации: x={0} y={1}",ob.x, ob.y);
Console.Write("Press any key to continue... ");
38
Console.Read();
}}}
39. Классы. Свойства.
Определение свойствСтандартное описание свойства имеет следующий синтаксис:
[модификаторы] тип_свойства имя_свойства
{
get { действия, выполняемые при получении значения свойства}
set { действия, выполняемые при установке значения свойства}
}
Модификаторы – модификаторы доступа.
Тип свойства – определяется типом значения с которым работает
свойство.
Имя свойства – правильный идентификатор.
В блоке get выполняются действия по получению значения свойства.
В блоке set устанавливается значение свойства.
Блоки get и set называются акссесорами или методами доступа (к
значению свойства).
Свойство ничего не хранит, оно выступает как посредник между
39
внешним кодом и переменной.
40. Классы. Свойства.
ПРИМЕРStudent student = new Student();
student.Name = “Иван”; // Работает блок Set
string studentName = student.Name; //Работает блок Get
Console.WriteLine(studentName); // Tom
class Student
{
private string name = “Новое”;
public string Name
{
get
{
return name; // возвращаеn значение свойства
}
set
{
name = value; // устанавливаеn новое значение свойства
}
}}
40
41. Классы. Свойства.
В классе Student определено поле name со спецификатором доступаprivate, поле хранит имя студента, и есть общедоступное свойство
Name. Они имеют практически одинаковое название за исключением
регистра.
Через свойство управляют доступом к переменной name.
В программе можно обращаться к этому свойству, как к обычному полю.
student.Name = “Петр”;
Свойства позволяют установить дополнительную логику, которая может
быть необходима при установке или получении значения.
Свойства только для чтения и записи
Блоки set и get не обязательно одновременно должны присутствовать в
свойстве. Если свойство определяет только блок get, то такое
свойство доступно только для чтения – можно получить его значение,
но не установить.
Если свойство имеет только блок set, тогда это свойство доступно
только для записи - можно только установить значение, но нельзя
получить.
41
42. Классы. Свойства.
ПРИМЕРclass Student
{
string name = "Tom";
int age = 1;
// свойство только для записи
public int Age
{
set { age = value; }
}
// свойство только для чтения
public string Name
{
get { return name; }
}
public void Print()=> Console.WriteLine($"Name: {name} Age: {age}");
}
42
43. Классы. Свойства.
ПРИМЕРStudent student = new Student();
// свойство для чтения - можно получить значение
Console.WriteLine(student .Name);
// student .Name = “Иван”; // ! Ошибка
student.Age = 18;
// Console.WriteLine(student .Age); // ! Ошибка
student.Print();
43
44. Классы. Свойства.
Вычисляемые свойстваСвойства не всегда могут быть связаны с определенной переменной.
Они могут вычисляться на основе различных выражений
class Person
{
string firstName;
string lastName;
public string Name
{
get { return $"{firstName} {lastName}"; }
}
public Person(string firstName, string lastName)
{
this.firstName = firstName;
this.lastName = lastName;
}
}
44
45. Классы. Свойства.
Person tom = new("Tom", "Smith");Console.WriteLine(tom.Name); // Tom Smith
В данном случае класс Person имеет свойство Name, которое доступно
только для чтения и которое возвращает общее значение на основе
значений переменных firstName и lastName.
45
46. Классы. Свойства.
Модификаторы доступаМожно применять модификаторы доступа не только ко всему свойству,
но и к отдельным блокам get и set:
class Person
{
string name = "";
public string Name
{
get { return name; }
private set { name = value; }
}
public Person(string name) => Name = name;
}
46
47. Классы. Свойства.
Модификаторы доступаPerson tom = new("Tom");
// Ошибка - set объявлен с модификатором private
//tom.Name = "Bob";
Console.WriteLine(tom.Name); // Tom
Закрытый блок set можно использовать только в данном классе - в его
методах, свойствах, конструкторе.
47
48. Классы. Свойства.
При использовании модификаторов в свойствах следует учитывать рядограничений:
• Модификатор для блока set или get можно установить, если свойство
имеет оба блока (и set, и get)
• Только один блок set или get может иметь модификатор доступа, но
не оба сразу
• Модификатор доступа блока set или get должен быть более
ограничивающим, чем модификатор доступа свойства. Например,
если свойство имеет модификатор public, то блок set/get может иметь
только модификаторы protected и private
48
49. Классы. Свойства.
Автоматические свойстваСвойства управляют доступом к полям класса. Для управления
доступом к нескольким полям используются автоматические свойства.
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
Создаются поля для свойств, которые автоматически генерируется при
компиляции.
49
50. Классы. Свойства.
Автоматические свойстваАвтосвойствам
можно
присвоить
(инициализация автосвойств):
class Person
{
public string Name { get; set; } = "Tom";
public int Age { get; set; } = 37;
}
значения
по
умолчанию
Person tom = new();
Console.WriteLine(tom.Name); // Tom
Console.WriteLine(tom.Age); // 37
50
51. Классы. Свойства.
Автоматические свойстваАвтосвойства также могут иметь модификаторы доступа:
class Person
{
public string Name { private set; get;}
public Person(string name) => Name = name;
}
Можно убрать блок set и сделать автосвойство доступным только для
чтения. В этом случае для хранения значения этого свойства для него
неявно будет создаваться поле с модификатором readonly, поэтому
следует учитывать, что подобные get-свойства можно установить либо
из конструктора класса, либо при инициализации свойства.
51
52. Классы. Свойства.
class Person{
// через инициализацию свойства
public string Name { get; } = "Tom";
// через конструктор
public Person(string name) => Name = name;
}
52
53. Классы. Свойства.
Блок initСеттеры в свойствах могут определяться с помощью оператора init (от
слова "инициализация«) – этот блок init позволяет инициализировать
свойство.
Для установки значений свойств с init можно использовать
инициализатор, либо конструктор, либо при объявлении указать
значение.
После инициализации значений подобных свойств их значения изменить
нельзя - они доступны только для чтения.
ПРИМЕР
public class Person
{
public string Name { get; init; } = "Undefined";
}
Person person = new();
//person.Name = "Bob"; //Ошибка - после инициализации изменить
значение нельзя
53
Console.WriteLine(person.Name); // Undefined
54. Классы. Свойства.
Блок initВ данном случае класс Person для свойства Name вместо сеттера
использует оператор init. В итоге на строке
Person person = new();
предполагается создание объекта с инициализацией всех его свойств.
В данном случае свойство Name получит в качестве значения строку
"Undefined". Однако поскольку инициализация свойства уже произошла,
то на строке
person.Name = "Bob";
// Ошибка
Второй способ инициализации - через конструктор:
public class Person
{
public Person(string name) => Name = name;
public string Name { get; init; }
}
Person person = new("Tom");
Console.WriteLine(person.Name); // Tom
54
55. Классы. Свойства.
Блок initТретий способ - через инициализатор:
public class Person
{
public string Name { get; init; } = "";
}
Person person = new() { Name = "Bob"};
Console.WriteLine(person.Name); // Bob
55
56. Классы. Свойства.
Сокращенная запись свойствПоскольку блоки get и set представляют специальные методы, то как и
обычные методы, если они содержат одну инструкцию, можно сократить
с помощью оператора =>:
class Person
{
string name;
public string Name
{
get => name;
set => name = value;
}
}
Можно сокращать все свойство в целом:
class Person
{
string name;
// эквивалентно public string Name { get { return name; } }
56
public string Name => name;
}
57. Классы. Свойства.
Модификатор requiredУказывает, что поле или свойства с этим модификатором обязательно
должны быть инициализированы.
public class Person
{
public required string Name { get; set; }
public required int Age { get; set; }
}
Person tom = new Person();
инициализированы
// ошибка - свойства Name и Age не
Person tom = new Person { Name = "Tom", Age = 38 }; // ошибки нет
Причем не важно, устанавливаем эти свойства в конструкторе или
инициализируем при определении, все равно надо использовать
инициализатор для установки их значений.
57
58. Классы. Свойства.
Модификатор requiredНапример, в следующем примере мы получим ошибку:
public class Person
{
public Person(string name)
{
Name = name;
}
public required string Name { get; set; }
public required int Age { get; set; } = 22;
}
Person bob = new Person("Bob"); // ошибка - свойства Name и Age все
равно надо установить в инициализаторе
58
59. Классы. Описание класса.
Организация работ при описании класса.Атрибут partial
При эксплуатации класса (когда он участвует в эксплуатации какого-то
приложения), существуют участки описания класса, которые
относительно постоянны.
Например, такие элементы класса, как описание полей, свойства и
конструкторы, относительно постоянны, но не методы, которые могут
часто изменять.
Имеет смысл большие классы разбивать на части, присваивая частям
атрибут partial (частичный). Тогда можно отдельно заниматься только
той частью, которая требует модификации, не трогая остальные
части.
При компиляции компилятор соберет все частичные классы в один
общий класс.
59
60. Классы. Описание класса.
Процесс создания частичных классов:• разносят общий (длинный) файл с расширением cs на несколько
файлов с таким же расширением и именами, помещая в них
необходимые элементы (конструкторы, методы, поля свойства).
• каждому файлу добавляют описатель partial.
• эти файлы подключают к общему проекту (создают проект с
программой Main()).
• файлы с расширением cs формируют с помощью программы
WordPad (при записи текстового файла дают ему расширение cs).
(Объединяют эти файлы в один, зайдя в меню среды
программирования: Project | Add | Existing Item. Откроется диалоговое
окно для поиска файлов. Надо найти ранее сформированные cs-файлы
и подключить.)
60
61. Классы. Описание класса.
ПРИМЕР// Первый частичный класс
partial class Employee
{ // Поля класса
private string empName; // имя
private int empID; // табельный номер
private float currPay; // зарплата
private int empAge; // возраст
private string empSSN; // номер медицинского полиса
private static string companyName; // название компании
// Конструкторы
public Employee() { }
public Employee(string name, int age, int id, float pay, string ssn)
{ // Инициализация свойств
Name = name;
Age = age;
ID = id;
Pay = pay;
SocialSecurityNumber = ssn;}
61
62. Классы. Описание класса.
ПРИМЕРstatic Employee() // Статический конструктор
{
companyName = “Объединение корпораций”;
}}
// Второй частичный класс
partial class Employee
{ // Свойства
public static string Company
{
get { return companyName; }
set { companyName = value; }
}
public string Name
{
get { return empName; }
set {
if (value.Length > 9) Console.WriteLine("Имя больше 9 символов");
else empName = value;
}}
62
63. Классы. Описание класса.
ПРИМЕРpublic int ID
{
get { return empID; }
set { empID = value; }
}
public float Pay
{
get { return currPay; }
set { currPay = value; }
}
public int Age {
get { return empAge; }
set { empAge = value; }
}
public string SocialSecurityNumber {
get { return empSSN; }
set { empSSN = value; }
}}
63
64. Классы. Описание класса.
ПРИМЕРusing System;
namespace app_employee_all
{
class Program
{
public static void Main()
{
Console.WriteLine("Собранная из частичных файлов программа");
Employee emp = new Employee {Name="Иванов"};
// Инициализация свойства через синтаксис инициализации
Console.WriteLine("Cотрудник компании: {0}", emp.Name);
Console.Write("Press any key to continue... ");
Console.ReadKey(true);
}}}
64
programming