понедельник, 12 марта 2018 г.

класи

Класи: основні поняття, дані, методи, конструктори, властивості

класи

Основні поняття
Клас - це узагальнене поняття, що визначають характеристики і поведінку деякого безлічі об'єктів, званих екземплярами класу. "Класичний" клас містить дані, що визначаютьвластивості об'єктів класу , і методи, що визначають їх поведінку. Для Windows-додатків в клас додається третя складова - події, на які можереагувати об'єкт класу. Всі класи бібліотеки .Net, а також всі класи, які створює програміст в середовищі .Net, мають одного загального предка - клас object .
Всі програми, розглянуті раніше, складалися з одного класу з одним методом Main і декількома допоміжними статичними методами. Тепер розглянемо поняття "клас" більш детально.
Опис класу містить ключове слово class, за яким слід його ім'я , а далі в фігурних дужках - тіло класу. Крім того, для класу можна задати його базові класи (предки) і ряд необов'язкових атрибутів і специфікаторів, що визначають різні характеристики класу:
[Атрибути] [специфікатор] class ім'я_класу [: предки] 
{Тело_класса}
Найпростіший приклад класу:
class Demo {}
Специфікатори визначають властивості класу, а також доступність класу для інших елементів програми. Можливі значення специфікаторів перераховані в наступній таблиці:
специфікаторопис
1newЗадає новий опис класу замість успадкованого від предка. Використовується для вкладення класів (в ієрархії об'єктів).
2publicДоступ до класу не обмежений
3protectedДоступ тільки з даного або похідного класу. Використовується для вкладених класів.
4internalДоступ лише з даної програми (збірки).
5protected internalДоступ тільки з даного та похідного класу і з даної програми (збірки).
6privateДоступ лише з елементів класу, всередині яких описаний даний клас. Використовується для вкладених класів.
7staticСтатичний клас. Дозволяє звертатися до методів класу без створення екземпляра класу
8sealedБезплідний клас. Забороняє успадкування даного класу. Застосовується в ієрархії об'єктів.
9abstractАбстрактний клас. Застосовується в ієрархії об'єктів.
Специфікатори 2-6 називаються специфікаторами доступу . Вони визначають, звідки можна безпосередньо звертатися до даного класу. Специфікатори доступу можуть комбінуватися з іншими специфікаторами.
Зауваження . Атрибути будуть розглянуті пізніше.
Клас можна описувати безпосередньо всередині простору імен або всередині іншого класу. В останньому випадку клас називається вкладеним. Залежно від місця опису класу деякі з цих специфікаторів можуть бути заборонені. В даному розділі ми розглянемо класи, які описуються безпосередньо в просторі імен. Для таких класів допускаються тільки два специфікатор: public і internal . За замовчуванням, тобто якщо жоден специфікатор доступу не вказано, мається на увазі специфікатор internal .
Об'єкти створюються явним або неявним чином, тобто або програмістом, або системою. Програміст створює екземпляр класу за допомогою операції new, наприклад:
Demo a = new Demo (); // Створюється екземпляр класу Demo
Якщо достатній для зберігання об'єкта обсяг пам'яті виділити не вдалося, то генерується виключення OutOfMemoryException .
Для кожного об'єкта при його створенні в пам'яті виділяється окрема область, в якій зберігаються його дані. У класі можуть бути присутнімистатичні елементи , які існують в єдиному екземплярі для всіх об'єктів класу. Статичні дані часто називають даними класу, а решта - даними примірника. Для роботи з даними класу використовуються статичні методи класу, для роботи з даними примірника -методи примірника , або просто методи.
До сих пір ми використовували в програмах тільки дані (змінні і константи) і методи. У загальному випадку клас може містити наступні функціональні елементи:
  1. Дані: змінні або константи.
  2. Методи, що реалізують не тільки обчислення, а й інші дії, що виконуються класом або його примірником.
  3. Конструктори (реалізують дії по ініціалізації екземплярів або класу в цілому).
  4. Властивості (визначають характеристики класу відповідно до способами їх завдання і отримання).
  5. Деструктори (визначають дії, які необхідно виконати до того, як об'єкт буде знищений).
  6. Індексатори (забезпечують можливість доступу до елементів класу по їх порядковому номеру).
  7. Операції (задають дії з об'єктами за допомогою знаків операцій).
  8. Події (визначають повідомлення, які може генерувати клас).
  9. Типи (типи даних, внутрішні по відношенню до класу).
В даному розділі ми розглянемо перші чотири категорії елементів класу
Перш ніж приступити до проектування класів, необхідно поговорити про присвоєнні і порівнянні об'єктів. Механізм виконання присвоювання один і той же для величин будь-якого типу, як посилального, так і розмірного, проте результати різняться. При присвоєнні значення копіюється значення, а при присвоєнні посилання - посилання, тому після присвоювання одного об'єкта іншому ми отримаємо два посилання, що вказують на одну і ту ж область пам'яті:
13_01
Нехай були створені три об'єкти а , b і з , а потім виконано присвоювання b = з . Тепер посилання b і з вказують на один і той же об'єкт. Старе значення b стає недоступним і очищається складальником сміття.
Аналогічна ситуація з операцією перевірки на рівність. величинизначимого типу рівні, якщо рівні їх значення. Величини посилального типу рівні, якщо вони посилаються на одні й ті ж дані. Так, об'єкти b і з рівні, тому що вони посилаються на одну і ту ж область пам'яті. Але а не дорівнює b навіть за однакової кількості їх значень.
Дані: поля і константи
Дані, що містяться в класі, можуть бути змінними або константами і задаються відповідно до правил, розглянутими в темі "Ідентифікатори". При описі даних також можна вказувати атрибути і специфікатор, що задають різні характеристики елементів. Синтаксис опису елемента даних наведено нижче:
[Атрибути] [специфікатор] [const] тип ім'я [= початкове_значення]
Розглянемо можливі специфікатор для даних:
специфікаторопис
1newНове опис поля, яке приховує успадкований елемент класу
2publicДоступ до елементу не обмежений
3protectedДоступ тільки з даного та похідних класів
4internalДоступ лише з даної збірки
5protected internalДоступ тільки з даного та похідних класів і з даної збірки
6privateДоступ тільки з даного класу
7staticОдне поле для всіх екземплярів класу
8readonlyПоле доступне тільки для читання (значення таких полів можна встановити або при описі, або в конструкторі)
9volatileПоле може змінюватися іншим процесом або системою
Зауваження . Атрибути будуть розглянуті пізніше.
Для констант можна використовувати тільки специфікатор 1-6.
За замовчуванням елементи класу вважаються закритими private . Для полів класу цей вид доступу є кращим, оскільки поля визначають внутрішню будову класу, яке повинно бути приховано від користувача. Всі методи класу мають безпосередній доступ до його закритим полях.
Поля, описані з специфікатором static , а також константи існують в єдиному екземплярі для всіх об'єктів класу, тому до них звертаються не через ім'я екземпляра, а через ім'я класу. Звернення до поля класу виконується за допомогою операції доступу (точка). Праворуч від точки задається ім'я поля, зліва - ім'я екземпляра для звичайних полів або ім'я класу для статичних. Розглянемо приклад створення класу Demo і два способи звернення до його полях.
class Circle
{
 public int x = 0;
 public int y = 0;
 public int radius = 3;
 public const double pi = 3.14;
 public static string name = "Коло";
 double p;
 double s;
}

class Program
{
 static void Main ()
 {
  Circle cr = new Circle (); // створення екземпляра класу
  Console.WriteLine ( "pi =" + Circle.pi); // звернення до константи
  Console.Write (Circle.name); // звернення до статичного полю
  // звернення до звичайних полях
  Console.WriteLine ( "з центром в точці ({0}, {1}) і радіусом {2}", cr.x, cr.y, cr.radius);
  // Console.WriteLine (cr.p); - викличе помилку, тому що поле p має тип private
               
  Console.Write ( "Введіть коефіцієнт =");
  int kof = int.Parse (Console.ReadLine ());
  cr.x - = kof; cr.y + = kof; cr.radius * = kof;
  Console.WriteLine ( "Нова окружність з центром в точці ({0}, {1}) і радіусом {2}",
  cr.x, cr.y, cr.radius);
  //cr.s = 2 * Circle.pi * cr.radius; - викличе помилку, тому що поле s має тип private
 }
}
методи
Зауваження . Створення і використання методів було розглянуто нами раніше. Тепер розглянемо використання методів в контексті створення класів.
Методи знаходяться в пам'яті в єдиному екземплярі і використовуються всіма об'єктами одного класу спільно, тому необхідно забезпечити роботу методів нестатичних примірників з полями саме того об'єкту, для якого вони були викликані. Для цього в будь-який нестатичних метод автоматично передається прихований параметр this, в якому зберігається посилання на який викликав функцію екземпляр.
В явному вигляді параметр this застосовується для того, щоб повернути з методу посилання на який викликав об'єкт, а також для ідентифікації поля в разі, якщо його ім'я збігається з ім'ям параметра методу, наприклад:

class Circle
{
 public int x = 0;
 public int y = 0;
 public int radius = 3;
 public const double pi = 3.14;
 public static string name = "Коло";
  public Circle T () // метод повертає посилання на екземпляр класу
 {
  return this;
 }
 public void Set (int x, int y, int r) 
 {
  this.x = x;
  this.y = y;
 radius = r;
 }
}

class Program
{
 static void Main ()
 {
  Circle cr = new Circle (); // створення екземпляра класу
  Console.WriteLine ( "pi =" + Circle.pi); // звернення до константи
  Console.Write (Circle.name); // звернення до статичного полю
  // звернення до звичайних полях
  Console.WriteLine ( "з центром в точці ({0}, {1}) і радіусом {2}", cr.x, cr.y, cr.radius);      
  cr.Set (1, 1, 10);
  Console.WriteLine ( "Нова окружність з центром в точці ({0}, {1}) і радіусом {2}", 
     cr.x, cr.y, cr.radius);
  Circle b = cr.T (); // отримуємо посилання на об'єкт cr, аналог b = c
  Console.WriteLine ( "Новий канал на коло з центром в точці ({0}, {1}) 
       і радіусом {2} ", bx, by, b.radius);
  }
}

Робота з файловою системою

Работа з файлової системою: класи Directory і Filе і класи DirectoryInfo і FileInfo

Робота з файловою системою

У просторі імен System.IO передбачено чотири класи, які призначені для роботи з файловою системою комп'ютера, тобто для створення, видалення перенесення і т.д. файлів і каталогів.
Перші два типи - Directory і Fi1е реалізують свої можливості за допомогою статичних методів, тому дані класи можна використовувати без створення відповідних об'єктів (екземплярів класів).
Наступні типи - DirectoryInfo і FileInfo мають схожі функціональними можливостями c Directory і Fi1е , але породжені від класу FileSystemInfo і тому реалізуються шляхом створення відповідних примірників класів.
Зауваження . Перед вивченням даної лекції скопіюйте на диск d свого комп'ютера архів prim . Уважно вивчіть вміст даного архіву.

Робота з каталогами

Абстрактний клас FileSystemInfo
Значна частина членів FileSystemInfo призначена для роботи з загальними характеристиками файлу або каталогу (мітками часу, атрибутами і т. П.). Розглянемо деякі властивості FileSystemInfo :

властивістьопис
AttributesДозволяє отримати або встановити атрибути для даного об'єкта файлової системи. Для цього властивості використовуються значення і перерахування FileAttributes
CreationTimeДозволяє отримати або встановити час створення об'єкта файлової системи
ExistsМоже бути використано для того, щоб визначити, чи існує даний об'єкт файлової системи
ExtensionДозволяє отримати розширення для файлу
FullNameПовертає ім'я файлу або каталогу з зазначенням шляху до нього в файлової системі
LastAccessTimeДозволяє отримати або встановити час останнього звернення до об'єкта файлової системи
LastWriteTimeДозволяє отримати або встановити час останнього внесення змін до об'єкта файлової системи
NameПовертає ім'я зазначеного файлу. Це властивість доступно тільки для читання. Для каталогів повертає ім'я останнього каталогу в ієрархії, якщо це можливо. Якщо немає, повертає повністю певне ім'я
У FileSystemInfo передбачено і кілька методів. Наприклад, метод Delete () - дозволяє видалити об'єкт файлової системи з жорсткого диска, a Refresh () - оновити інформацію про об'єкт файлової системи.
клас DirectoryInfo
Даний клас успадковує члени класу FileSystemInfo і містить додатковий набір членів, які призначені для створення, переміщення, видалення, отримання інформації про каталогах і підкаталогах в файлової системі. Найбільш важливі члени класу містяться в наступній таблиці:

членопис
Create () CreateSubDirectory ()Створюють каталог (або підкаталог) за вказаною шляху в файлової системі
Delete ()Видаляє порожній каталог
GetDirectories ()Дозволяє отримати доступ до підкаталогам поточного каталогу (у вигляді масиву об'єктівDirectoryInfo )
GetFiles ()Дозволяє отримати доступ до файлів поточного каталогу (у вигляді масиву об'єктів FileInfo )
MoveTo ()Переміщує каталог і весь його вміст на нову адресу в файлової системі
Parentповертає батьківський каталог в ієрархії файлової системи
Робота з типом DirectoryInfo починається з того, що ми створюємо екземпляр класу (об'єкт), вказуючи при виклику конструктора в якості параметра шлях до потрібного каталогу. Якщо ми хочемо звернутися до поточного каталогу (тобто каталогу, в якому в даний час проводиться виконання програми), замість параметра використовується позначення "." наприклад:
// Створюємо об'єкт DirectoryInfo, якому буде звертатися до поточного каталогу
DirectoryInfo dir1 = new DirectoryInfo ( ".");
// Створюємо об'єкт DirectoryInfo, якому буде звертатися до каталогу d: \ prim
DirectoryInfo dir2 = new DirectoryInfo (@ "d: \ prim");
Якщо ми спробуємо створити об'єкт DirectoryInfo , зв'язавши його з неіснуючим каталогом, то буде згенеровано виняток System.IO.DirectoryNotFoundException . Якщо ж все нормально, то ми зможемо отримати доступ до даного каталогу. У прикладі, який наведений нижче, ми створюємо об'єкт DlrectoryInfo , який пов'язаний з каталогом d: \ prim , і виводимо інформацію про даний каталозі:
using System;
using System.Text;
using System.IO;

namespace MyProgram
{
 class Program
 {
  static void Main (string [] args)
  {
    DirectoryInfo dir = new DirectoryInfo (@ "d: \ prim");
    Console.WriteLine ( "*****" + dir.Name + "*****");
    Console.WriteLine ( "FullName: {0}", dir.FullName);
    Console.WriteLine ( "Name: {0}", dir.Name);
    Console.WriteLine ( "Parent: {0}", dir.Parent);
    Console.WriteLine ( "Creation: {0}", dir.CreationTime);
    Console.WriteLine ( "Attributes: {0}", dir.Attributes.ToString ());
    Console.WriteLine ( "Root: {0}", dir.Root);
   }
 }
}
Властивість Attributes дозволяє отримати інформацію про атрибути об'єкта файлової системи. Можливі значення даного властивості приведені в наступній таблиці:

значенняопис
ArchiveЦей атрибут використовується додатками при проведенні резервного копіювання, а в деяких випадках - видалення старих файлів
CompressedВизначає, що файл є стислим
DirectoryВизначає, що об'єкт файлової системи є каталогом
EncryptedВизначає, що файл є зашифрованим
HiddenВизначає, що файл є прихованим (такий файл не буде виводитися при звичайному перегляді каталогу)
NormalВизначає, що файл знаходиться в звичайному стані і для нього встановлені будь-які інші атрибути. Цей атрибут не може використовуватися з іншими атрибутами
OfflineФайл (розташований на сервері) кешуватися в сховище off-line на клієнтському комп'ютері. Можливо, що дані цього файлу вже застаріли
ReadonlyФайл доступний тільки для читання
SystemФайл є системним (тобто файл є частиною операційної системи або використовується виключно операційною системою)
Через DirectoryInfo можна не тільки отримувати доступ до інформації про поточний каталозі, але отримати доступ до інформації про його підкаталогах:
class Program
{
 static void printDirect (DirectoryInfo dir)
 {
  Console.WriteLine ( "*****" + dir.Name + "*****");
  Console.WriteLine ( "FullName: {0}", dir.FullName);
  Console.WriteLine ( "Name: {0}", dir.Name);
  Console.WriteLine ( "Parent: {0}", dir.Parent);
  Console.WriteLine ( "Creation: {0}", dir.CreationTime);
  Console.WriteLine ( "Attributes: {0}", dir.Attributes.ToString ());
  Console.WriteLine ( "Root: {0}", dir.Root);
 }

 static void Main (string [] args)
 {
  DirectoryInfo dir = new DirectoryInfo (@ "d: \ prim");
  printDirect (dir);
  DirectoryInfo [] subDirects = dir.GetDirectories ();
  Console.WriteLine ( "Знайдено {0} підкаталогів", subDirects.Length);
  foreach (DirectoryInfo d in subDirects)
  {
   printDirect (d);
  }
  }
}
Завдання . Перетворіть метод printDirect врекурсивний метод таким чином, щоб можна було переглянути інформацію про всіх підкаталогах поточного каталогу, незалежно від рівня вкладеності.
Метод CreateSubdirectory () дозволяє створити в обраному каталозі як єдиний підкаталог, так і безліч підкаталогів (в тому числі, і вкладених один в одного). Створимо в каталозі кілька додаткових підкаталогів:
DirectoryInfo dir = new DirectoryInfo (@ "d: \ prim");
dir.CreateSubdirectory ( "doc"); // створили підкаталог
dir.CreateSubdirectory (@ "book \ 2008"); // створили вкладений підкаталог
Завдання . Створіть вкладений підкаталог best \ 2008 рік для каталогу d: \ prim \ bmp .
Метод MoveTo () дозволяє перемістити поточний каталог по заданому в якості параметра адресою. При цьому можливо зробити перейменування каталогу. наприклад:
DirectoryInfo dir = new DirectoryInfo (@ "d: \ prim \ bmp");
dir.MoveTo (@ "d: \ prim \ letter \ bmp");
В даному випадку каталог bmp переміщається в за адресою d: \ prim \ letter \ bmp . Так як ім'я переміщуваного каталогу збігається з крайнім правим ім'ям в адресі нового місця розташування каталогу, то перейменування не відбувається. Наступний приклад дозволить нам перейменувати поточний каталог:
DirectoryInfo dir = new DirectoryInfo (@ "d: \ prim \ letter");
dir.MoveTo (@ "d: \ prim \ archive");
клас Directory
Працювати з каталогами файлової системи комп'ютера можна і за допомогою класу Directory , функціональні можливості якого багато в чому збігаються з можливостями DirectoryInfo . Але члени даного класу реалізовані статично, тому для їх використання немає необхідності створювати об'єкт.
Розглянемо роботу з методами даного класу на прикладах.
Зауваження . Видаліть з диска d змінену папку prim . І ще раз скопіюйте її вихідну версію з розділу 12 цього електронного підручника.
Directory.CreateDirectory (@ "d: \ prim \ 2008"); // створили підкаталог 2008
Directory.Move (@ "d: \ prim \ bmp", 
             @ "D: \ prim \ 2008 рік \ bmp"); // перенесли каталог bmp в каталог 2008
Directory.Move (@ "d: \ prim \ letter", 
             @ "D: \ prim \ archives"); // перейменували каталог letter в archives

Зауваження .
  1. Видалення каталогу можливо тільки тоді, коли він порожній.
  2. На практиці комбінують використання класів Directory і DirectoryInfo .