- •Тема 1 Програмна технологія Microsoft .Net. Вступ
- •Загальна характеристика платформи .Net Framework
- •Єдине середовище виконання clr
- •Єдина система типів cts
- •Бібліотека базових типів bcl
- •Розбір найпростішої програми на мові с
- •Загальна структура програми на мові c#
- •Створення .Net-додатків з використанням csc.Exe
- •Тема 2 Класи в c# Вступ
- •Створення .Net-додатків на мові c# з використанням ide Visual с# 2010 Express
- •Синтаксис опису класу
- •Поля класу
- •Методи класу
- •Властивості та індексатори
- •Конструктори
- •Деструктор
- •Перевантаження операцій
- •Частинні випадки класу
- •Структура «Раціональне число»
- •Тема 3 Основні засоби розробки класів у c# Вступ
- •Успадкування
- •Поліморфне успадкування
- •Агрегація та композиція
- •Абстрактні класи
- •Інтерфейси
- •Тема 4 Узагальнення Поняття узагальнених класів
- •Обмеження (constraints) для параметрів типу
- •Узагальнені методи
- •Узагальнені інтерфейси
- •Недолік обмеження операцій
Методи класу
Методи визначають операції, які можуть виконувати об’єкти класу. Метод можна розглядати як перетворювач деяких вхідних даних у результат (вихідні дані методу). Неявним параметром є той об’єкт, який викликає даний метод. Доступ до нього можна одержати за допомогою ключового слова this. Для визначення методу класу в C# використовується синтаксис:
[атрибути] [модифікатори] тип_значення ім’я_методу (список_форм_параметрів) { тіло_методу [return значення]; } |
Методи можуть повертати значення. Тип значення, яке повертає метод визначається типом даних результату. Якщо тип значення, що повертається, не дорівнює void, то для повернення значення використовується ключове слово return. Крім того, ключове слово return зупиняє виконання методу. Тобто, якщо тип значення, що повертається, void, то інструкцію return без значення також можна використовувати для завершення виконання методу. Якщо ключове слово return відсутнє, то виконання методу завершиться, коли буде досягнуто кінець його блоку коду. Для повернення значень методами з типом значення, що повертається, відмінним від void необхідно обов’язково використовувати ключове слово return.
Список формальних параметрів методу – це список імен об’єктів із вказанням їх типів, які є вхідними даними методу:
[специфікатор] тип1 ім’я1, [специфікатор] тип2 ім’я2, ..., [специфікатор]типN ім’яN |
Звертання до методу відбувається за допомогою його виклику, при якому на місце формальних параметрів підставляються фактичні параметри (аргументи). Типи аргументів повинні збігатися з типами даних відповідних формальних параметрів.
Статичні методи. Як і у випадку полів класу до методів може також застосовуватися модифікатор static. Виклик таких методів також здійснюється на рівні класу:
Ім'я_класу.Ім'я_методу(список_аргументів); |
Статичні методи призначені для обробки даних класу. Тобто, нестатичні поля в таких методах недоступні. Static-методи часто застосовуються в стандартних бібліотеках. Наприклад, методи ReadLine() і WriteLine() є статичними в класі Console, метод Parse – статичний у класах Int32, Float, Double.
Передача параметрів типів-значень та посилальних типів. Список формальних параметрів методу може бути порожнім. Наприклад:
class Rational { ... //метод виводу раціонального числа на екран void Display() { if (denominator == 1) { Console.WriteLine("R_{0}: {1}", ID, numerator); } else Console.WriteLine("R_{0}: {1}/{2}", ID, numerator, denominator); } } |
У випадку, коли список формальних параметрів не порожній, вхідні (фактичні) параметри передаються в метод за значенням або за посиланням10. За замовчуванням параметри передаються за значенням. Це означає, що в методі створюється копія даного об’єкта, і всі дії відбуваються саме з нею. При завершенні роботи методу ця копія знищується, а значення вхідного параметра залишається незмінним.
class Rational { ... //метод, що повертає найменше із двох раціональних чисел static Rational Min(Rational arg1, Rational arg2) { if (arg1.numerator * arg2.denominator < arg2.numerator * arg1.denominator) return arg1; else return arg2; } } |
Якщо у метод передається об’єкт посилального типу даних, то через посилання (адресу цього об’єкту) надається доступ до полів цього об’єкта. При цьому всі зміни, зроблені з полями об’єкта в методі, збережуться й після завершення його роботи, але значення самого посилання в методі змінити не можна. Коли необхідно змінити значення деякого параметра усередині методу, у тому числі й посилання на об’єкт, його описують як ref-параметр або out-параметр.
Для роботи з ref-параметром визначення методу та виклик методу повинні явно використовувати ключове слово ref. Слід мати на увазі, що об’єкт, який передається як ref-параметр має бути ініціалізованим.
class Rational { ... //метод, що обмінює значеннями два раціональні числа static void Reverse(ref Rational arg1, ref Rational arg2) { Rational temp = arg1; arg1 = arg2; arg2 = temp; } } |
Ключове слово out також використовується для передачі аргументів за посиланням. Але на відміну від ключового слова ref не вимагає ініціалізації змінної перед її передачею. Та незважаючи на те, що змінні, передані в якості out-аргументів можуть не ініціалізуватися перед передачею у метод, всередині методу їм обов’язково мають бути присвоєні значення (метод обов’язково повинен записати в них якесь значення) до моменту повернення результату методом. Нагадаємо, що за визначенням метод може повертати в якості результату тільки один об’єкт, тип якого визначений як тип значення, що повертається методом. Проте, нерідко виникають задачі, в яких результатом роботи методу повинні бути два або більше значень. Саме в цьому випадку і можна використати в методі формальні out-параметри.
Ключові слова ref і out по-різному обробляються під час виконання, але в режимі компіляції вони рівноцінні.
Методи зі змінною кількістю параметрів. Часто при реалізації класів виникає необхідність у методі, який здатен виконувати певну дію при різній кількості вхідних даних. Наприклад для нашого класу є потреба у методі, який би повертав найменше не тільки серед двох заданих раціональних чисел, але і трьох, чотирьох і т.д. У таких випадках говорять про метод зі змінною кількістю параметрів, які повинні мати однаковий тип даних. При виклику такого методу з його фактичних параметрів формується масив який передається далі у метод. Формальний параметр, що задає цей масив, описується ключовим словом params і повинен розташовуватися в списку параметрів методу останнім.
class Rational { ... //метод Min, що повертає найменше серед набору раціональних чисел static Rational Min(params Rational[] arg) { if (arg.Length > 0) { Rational min = arg[0]; for (int i = 1; i < arg.Length; i++) if (arg[i].numerator * min.denominator < min.numerator * arg[i].denominator) min = arg[i]; return min; } else throw new ArgumentException("Не задано жодного аргументу!"); } } |
Рекурсивні методи. Рекурсивні методи – це функції, у тілі яких міститься виклик самих себе. Звичайно їх використовують у ситуаціях, коли легко звести вихідну задачу до задачі того ж виду, але з іншими вихідними даними. Застосування рекурсивних методів вважається дуже витратним з погляду пам’яті та не підходить для розв’язання задач великої розмірності. Проте, існує багато задач, у яких рекурсивні алгоритми більш прості та дають компактні програми. Слід пам’ятати, що будь-який рекурсивний метод повинен мати обов’язкову умову виходу з рекурсії. При виконанні цієї умови керування передається в місце попередньої ітерації, звідки відбувся рекурсивний виклик або у функцію, що викликала даний метод.
Відзначимо, що рекурсивні методи можуть бути як статичними, так і методами об’єкта, тобто викликатися для екземпляра класу.
Наприклад у нашому класі Rational можна реалізувати рекурсивний метод для визначення НСД двох натуральних чисел із подальшим його використанням у методі скорочення дробу.
class Rational { ... //рекурсивний метод, що повертає НСД static int GCD(int a, int b) { //умова виходу з рекурсії if (b == 0) return a; else return GCD(b, a % b); } //метод скоррочення дробу static void Reduce(Rational arg) { int gcd = Rational.GCD(Math.Abs(arg.numerator), arg.denominator); arg.numerator /= gcd; arg.denominator /= gcd; } } |
Перевантаження методів. Іноді виникає необхідність робити однакову обробку для різних типів даних. У цьому випадку зручно визначати декілька методів з однаковим іменем для різних типів даних. Такий прийом називають перевантаженням функцій (методів). Перевантажені методи повинні мати різні списки формальних параметрів. Значення, що повертаються перевантаженими функціями також можуть різнитися, але це не повинно бути єдиною відмінністю. Такий прийом часто використовується в бібліотечних класах. Наприклад, у класі Console для виводу (друку) якого-небудь повідомлення існує 19 перевантажених методів WriteLine():
WriteLine() – записує поточну ознаку кінця рядка в стандартний вихідний потік;
WriteLine(double) – записує текстове представлення дійсного числа в стандартний вихідний потік;
WriteLine(String) – записує заданий рядок у стандартний вихідний потік;
WriteLine(String, object[]) – записує текстові представлення заданого масиву об’єктів у стандартний вихідний потік з використанням заданих відомостей про форматування і т.д.
У нашому класі Rational вже є два перевантаження методу Min().
