660 likes | 817 Views
Тема № 4. Об ’ єктні властивості C#. ООП у C#: найбільш помітні особливості. C# – повністю об ’ єктно-орієнтована мова . Всі змінні – об ’ єкти . Немає множинного спадкування класів. Доступ до екземплярів Reference Type здійснюється виключно через указники на них.
E N D
Тема №4 Об’єктні властивості C#
ООП у C#: найбільш помітні особливості • C# – повністю об’єктно-орієнтована мова. • Всі змінні – об’єкти. • Немає множинного спадкування класів. • Доступ до екземплярів Reference Type здійснюється виключно через указники на них. • Відсутній аналог delete. • Методи класу можуть бути перевантажені, розрізнення – за сигнатурою. • Можна визначати операції, в т.ч. індексатори. • Властивості. • За замовченням параметри методів передаються за значенням, це можна змінювати.
Особливості ООП у C# - продовження • На вершині ієрархії – клас Object. • Поліморфізм: за замовченням методи невіртуальні; це можна змінювати. • Вводяться інтерфейси як абстракція, що тільки декларує поведінку, але не визначає її. • Неявно типовані змінні. • Generics. • Ініціалізатори класів. • Розвинені засоби RTTI та інтроспекції. • Часткові класи. • Анонімні класи та анонімні методи. • Делегати. • Події.
Особливості ООП у C#: продовження • Розширюючі методи. • Риси, характерні для функціонального програмування (ламбда-вирази і т.п). • LINQ.
Класи і об’єкти • Поняття класу та об’єкту в C# в цілому співпадає з загальноприйнятим. • Опис класу: class KlName { членикласу }
Reference Type: загальна характеристика • Загальна риса: доступ до змінних цих типів здійснюється через вказівники на них. • Але: змінні вказівникових типів ведуть себе подібно до вказівників. • Такими типами є, наприклад: екземпляри класів, в т.ч. рядки; масиви. • null - спеціальне значення для пустого вказівника.
Створення об’єктів. Конструктори • За допомогою оператора new: KlName ekz=new KlName(параметри); • І за синтаксисом, і за семантикою це виклик конструктора - спеціального методу, який описує, які дії повинні виконуватися при ініціалізації об’єкта. • Синтаксично - метод, ім’я якого співпадає з іменем класу. Нічого не повертає (навіть void). • Конструктори можуть бути перевантажені. • Якщо конструкторів немає - надається конструктор за замовченням. • Але, якщо є хоча б один конструктор - конструктор за замовченням не надається.
Характерний приклад Нехай є клас Kl і оголошення Kl ekz; Чи означає це оголошення створення екземпляру класу і виділення пам’яті під нього? Ні, створюється лише вказівник відповідного типу. Сам екземпляр створюється шляхом виклику конструктора класу: Kl ekz = new Kl(…); Аналогічно - операції.
Екземпляри класів vN1a vN2a a N1 N2 vN1b vN2b b N1 N2 b=a; b.N1=vNEW; вив. a.N1; //vNEW
Рядки: особливість (рядки є незмінюваними) “AAAA” a “BBBB” b “CCCC” b=a; b=“CCCC”; вив. а; //AAAA
Модифікатори доступу • public – загальнодоступні; • protected – доступні для підкласів; • internal – доступні для класів в межах тієї ж збірки; • internal protected – доступні для підкласів, а також для будь-яких класів у межах збірки; • private - тільки для класу, в якому вони визначені (для членів класу – за замовченням).
Запитання Чи може конструктор класу бути приватним?
Використання приватних конструкторів: паттерн Singleton Singleton - Singleton instance = new Singleton() - Singleton() + Singleton getInstance() return instance;
Поняття властивості • Концепція властивостей є однією з найбільш характерних рис C#. • Властивість – це конструкція, яка передбачає методи get та/або set для отримання або встановлення відповідного значення.
Приклад властивості (“класичний” синтаксис) У класі: int QP; public int Q { get { return QP; } set { QP = value; } } У клієнті, який використовує клас: sp.Q = 2;
Властивості: коментар до прикладу • Ззовні звернення до властивості виглядає як звернення до поля. • У найбільш типовому випадку властивість пов’язана з окремим полем, але це не обов’язково. У цьому випадку може бути так, що деяка властивість L встановлюється в одне значення, а при зчитуванні отримуємо інше значення. • Якщо потрібно тільки для читання або для запису – тільки get або, відповідно, set.
Приклад public int L { get { return QP + LP; } set { LP = value; } }
З 2.0 – можливість розділення прав доступу • В С# 2.0 з’явилася можливість розділити права доступу для селекторів (get) і модифікаторів (set). • Приклад: public int L { get { return QP + LP; } private set { LP = value; } }
Новий спрощений синтаксис для властивостей – з C# 3.0 public int R { get;set; }
Новий синтаксис ініціалізації об’єктів – з C# 3.0 Kl s1 = new Kl { R = 30 }; Семантично цееквівалентно виклику конструктора класу без параметрів і встановленню значень полів або властивостей.
Cпадкування class K1 : K2 { . . . } К1-підклас; К2-суперклас. Так само, як і Java, C# не підтримує множинного спадкування. На вершині ієрархії – клас System.Object.
Закриті класи і методи • Модифікатор sealed. • Для класів цей модифікатор означає, що від цього класу не можна утворювати похідні класи. Таким є, наприклад, клас string. • Для методів цей модифікатор означає, що цей метод не можна перевизначати в підкласах.
Вказівники this та base • this - вказівник на даний екземпляр. • Передається методам екземпляра (нестатичним методам) як неявний параметр. • Одне з типових використань - в конструкторах. • base – посилання на суперклас (нестатичне).
Виклик іншого конструктора Того ж класу: public Kl(…):this(…) { … } Суперкласу: public Kl(…):base(…) { … }
Статичні поля і методи • Супроводжуються модифікатором static. • Поля і методи класу, а не екземпляру. • Для статичних полів - одна копія для всіх екземплярів; для нестатичних - кожний екземпляр має свою копію.Одне з типових використань - підрахунок кількості екземплярів класу. • Виклик - через ім’я класу. • З статичними полями і методами можна працювати, коли ще немає жодного екземпляра.
Статичні поля і методи: продовження • Статичні методи не можуть викликати нестатичні методи, а також звертатися до нестатичних полів. • Типовий механізм ініціалізації статичних полів – статичний конструктор, тобто конструктор з модифікатором static. • Статичним може бути і весь клас – якщо в ньому є лише статичні члени. Неможливо створити екземпляр такого класу; звернення до методів можуть бути тільки статичними.
Приклад статичного класу (ілюструється також readonly) static class Stalker { static readonly public int Pole; static Stalker() //статичний конструктор { Pole = 10; } static public void Metod() { Console.WriteLine(Pole); } }
Ланцюжки конструкторів • Перед виконанням конструктора підкласу автоматично викликається конструктор суперкласу.
Поліморфізм у C#: початок • Об’єктна змінна суперкласу може посилатися на екземпляр підкласу, або посиланню на суперклас може бути надано значення посилання на підклас (розширююче перетворення). • Розширююче перетворення здійснюється автоматично; знижуюче слід робити явно. • “Безпечне” приведення – as. • Перевірка типу – is.
Поліморфізм: віртуальні функції • Класичний приклад: оголошуємо клас Baseз методом Metodта його підклас Sub, в якому теж є метод Metod. Створюємо екземпляр класу Subі викликаємо метод Metod. Метод якого саме класу буде викликаний?
Віртуальні функції: загальні орієнтири • За замовченням методи C# не є віртуальними, але їх можна зробити віртуальними за допомогою модифікатора virtual. • Статичні, а також приватні методи не можуть бути віртуальними. • Важливі модифікатори: override – заміщення; new – затінення.
Демонстрація: Polimorf class Bas { public virtual void Metod() { Console.WriteLine("Base class"); } } class Der : Bas { public void Metod()// new чи override ? { Console.WriteLine("Derived class"); } }
Використання Bas b = new Der();//якщо var – може бути //інакше b.Metod();
Quiz: що виведе програма static void Main(string[] args){ D d = new D(); C c = d; B b = c; A a = b; d.M(); c.M(); b.M(); a.M(); Console.ReadLine(); } } class A { public virtual void M() { Console.Write("A"); } } class B:A { public override void M(){ Console.Write("B");} } class C : B { new public virtual void M() { Console.Write(“С");} } class D : C { public override void M(){Console.Write("D"); } }
Абстрактні методи і класи • Абстрактний метод - метод без реалізації; він супроводжується модифікатором abstract. • Передбачається, що такі методи повинні перевизначатися в підкласах. Тому абстрактні методи автоматично є віртуальними. • Абстрактні методи не мають тіла: public abstract int fun(); • Якщо клас містить хоча б один абстрактний метод, він сам повинен бути оголошений як абстрактний. • Для абстрактного класу не можна створювати екземпляри.
Інтерфейси • Логічний розвиток ідеї абстрактних класів. • Всі методи інтерфейсу є абстрактними і неявно є public (хоча явно вказувати ці модифікатори не дозволяється). • Інтерфейси не можуть містити полів (на відміну від Java). • Але інтерфейси можуть містити властивості. • В C# прийнято починати назви інтерфейсів з літери I, закінчуються вони часто на able.
Реалізація інтерфейсів • Можна сказати, що інтерфейс - це набір вимог, які висуваються до класу, що його реалізує. • Якщо клас реалізує інтерфейс, то він повинен визначити всі методи, які описані в інтерфейсі. • Синтаксис: class Kl : I {… • Клас може реалізувати декілька інтерфейсів; у цьому випадку вони перелічуються через кому. • Якщо, крім цього, клас Kl спадкує від іншого класу B та реалізує кілька інтерфейсів – class Kl: B,I1,I2,… • Між інтерфейсами може бути відношення спадкування, причому таке спадкування може бути множинним.
Приклад: інтерфейс interface I { int Pole { get; set; } void Metod(); } class Kl : I { public int Pole { get; set; } public void Metod() { Console.WriteLine("Interface implemented with field "+Pole); } }
Явна реалізація інтерфейсів. • Закриття методу інтерфейсу в класі; тоді для звернення до такого методу треба використовувати вказівник інтерфейсу. • Випадок, коли реалізується кілька інтерфейсів, і відповідний метод для кожного інтерфейсу потрібно визначити по-своєму.
Приклад явної реалізації інтерфейсів. Інтерфейси interface I1 { void Metod(); } interface I2 { void Metod(); }
Приклад явної реалізації інтерфейсів. Клас class Kl : I1,I2 { void I1.Metod() { Console.WriteLine("First Interface"); } void I2.Metod() { Console.WriteLine("Second Interface"); } }
Приклад явної реалізації інтерфейсів. Звернення I1 ekz1 = new Kl(); I2 ekz2 = (I2) ekz1; //один об’єкт – різні типи! ekz1.Metod(); ekz2.Metod();
Перевантаження операторів - приклад class Kl { public int Pole; public Kl(int Pole) { this.Pole = Pole; } public static Kl operator +(Kl a, Kl b) { return new Kl(a.Pole + b.Pole); } }
В основній програмі class Program { static void Main(string[] args) { Kl a = new Kl(10) + new Kl(15); Console.WriteLine(a.Pole); Console.ReadLine(); } }
Перевантаження операторів – деякі особливості • Всі оператори мають бути описані як public і static. • Не можна перевантажувати ряд операторів, зокрема =. • Якщо перевантажується +, то += перевантажується автоматично. • Можуть перевантажуватися trueта false (буде робитися приклад на цю тему). • Для операторів приведення типів може бути заданий явний або неявний режим виклику (див. наступний слайд).
Модифікатори explicit та implicit • Використовуються у визначеннях операторів приведення типів для задання того, чи буде перетворення здійснюватися неявно, чи приведення типів слід робити явним чином.
Приклад приведення типів: клас; неявне перетворення class Person { public String Name { get; set; } public String Citizen { get; set; } public static implicit operator String (Person p) {return String.Format("Name: {0} ; Citizen: {1}",p.Name,p.Citizen); } }
Використання неявного перетворення Person p1 = new Person { Name = "Bob Robber", Citizen = "UK" }; String s = p1; Console.WriteLine(s);
Клас: явне перетворення class Person { public String Name { get; set; } public String Citizen { get; set; } public static explicit operator String (Person p) {return String.Format("Name: {0} ; Citizen: {1}",p.Name,p.Citizen); } }
Явне перетворення: використання Person p1 = new Person { Name = "Bob Robber", Citizen = "UK" }; String s = (String)p1; Console.WriteLine(s);