3. Використання ключового слова this.
Ключове слово this у методі класу означає посилання на поточний екземпляр, тобто той, для якого був викликаний даний метод. Пригадаємо визначення класу Polar_Point . Він містив методи, що визначають декартові координати даної полярної точки. Наведемо ще раз тут окремо визначення цих методів:
public double xCoord() // абсциса полярної точки
{
return r * Math.Cos(phi);
}
public double yCoord() // ордината полярної точки
{
return r * Math.Sin(phi);
}
Обидва методи безпосередньо звертаються до членів класу r та phi без вживання складених імен, що включають ідентифікатори класу або екземпляру. Проте у тих самих методах можна використати посилання this , щоб підкреслити що використовуються дані-члени даного поточного екземпляру класу:
public double xCoord() // абсциса полярної точки
{
return this.r * Math.Cos(this.phi);
}
public double yCoord() // ордината полярної точки
{
return this.r * Math.Sin(this.phi);
}
Тоді, якщо у функції Main був створений екземпляр p1 класу Polar_Point
Polar_Point p1 = new Polar_Point();
то виклик методу p1.xCoord() або p1.yCoord() фактично означає, що значенням this є посиланням на екземпляр p1 , тобто this.r це p1.r , а this.phi це p1.phi. Зазвичай посилання this не використовується таким чином – у цьому просто немає необхідності.
Конструктор класу Polar_Point міг би також бути написаним із використанням this. Це дозволило б використати для формальних параметрів ті самі ідентифікатори, що й для членів класу. І хоча така практика не вважається ідеальним стилем програмування, наведемо тут код такого конструктору задля демонстрації використання посилання this.
public Polar_Point(double r, double phi)
{
// Конструктор – формальні параметри мають ті самі
// ідентифікатори, що й члени класу
this.r = r; this.phi = phi;
}
Якби тут не було використано посилання this , то формальні параметри конструктора double r, double phi перекривали б члени класу Polar_Point з такими самими ідентифікаторами, і не було б можливості їх проініціалізувати вказаними значеннями.
І нарешті, саме використання посилання this забезпечує можливість викликати конструкторами класу один одного. Це позбавляє від необхідності писати фрагменти коду, що дублюються. Конструктор, що звертається до іншого конструктору класу, має особливий синтаксис:
<специфікатор_доступу> <ідентифікатор_класу>
(<список_параметрів_конструктора_1>) :
this (<список_параметрів_конструктора_2>)
{
// код конструктора
}
Якщо об’єкт класу створюється таким конструктором, то спочатку викликається той конструктор класу, який має список параметрів, відповідний до <списку_параметрів_конструктора_2> з урахуванням приведення типів, а лише потім виконується код початкового конструктора, який може бути і порожнім взагалі. В цій синтаксичній конструкції this (<список_параметрів_конструктора_2>) називається ініціалізатором конструктору.
Повернемось до прикладу Overloading_Constructors, в якому визначається клас Circle . Файл Circle.cs змінимо наступним чином:
using System;
namespace Overloading_Constr_this
{
class Circle
{
public double x0, y0; // координати центру кола
public double r; // радіус кола
public Circle(double x0_, double y0_, double r_)
{ // Конструктор з трьома параметрами
x0 = x0_; y0 = y0_; r = r_;
Console.WriteLine("Створили коло - центр ({0};{1}),
радiус {2}", x0, y0, r);
}
public Circle(double r_) : this (0, 0, r_)
{ // Конструктор з одним параметром }
public Circle() : this(0, 0, 1)
{ // Конструктор без параметрів }
}
}
Зверніть увагу, що тут єдиним «діючим» конструктором є конструктор Circle(double x0_, double y0_, double r_), адже два інших конструктори не роблять нічого, просто звертаються через this саме до нього, вказуючи потрібні набори параметрів для ініціалізації.
Якщо у в основному файлі проекту записати наступний код
using System;
namespace Overloading_Constr_this
{
class Program
{
static void Main()
{
Circle c1 = new Circle();
Circle c2 = new Circle(10);
Circle c3 = new Circle(5, 4, 3);
}
}
}
то після запуску прикладу на виконання на екрані побачимо наступний результат:
Створили коло - центр (0;0), радiус 1
Створили коло - центр (0;0), радiус 10
Створили коло - центр (5;4), радiус 3
При створенні всіх цих об’єктів викликались 3 різних конструктори, проте повідомлення про створення кола, насправді надсилав лише один з них, до якого два інших звертались завдяки посиланню this.
Реалізація основних структур даних в мові C#
Часто виникає програмна необхідність у певній структуризації інформації та організації методів доступу до таких структур даних. Програміст, наприклад, може мати справу із переліком назв деяких товарів, або з більш складними наборами даних. Використання масивів в цьому випадку може бути зручним підходом, проте, по-перше, звертання до елементу за індексом не завжди зручне (наприклад, товари треба вибирати за ціною), по-друге масиви мають один дуже суттєвий недолік – їх розмір фіксований і у випадках, коли кількість елементів наперед невідома, необхідно створювати масив іншого розміру перед зміною кількості елементів. Таку операцію можна виконувати наступним чином:
using System;
namespace LabDemo
{
class Program
{
static void Main(string[] args)
{
const int NEWSIZE = 10; // кількість елементів
int[] arr1 = { 1, 2, 3, 4, 5 };
// створюємо та ініціалізуємо новий масив
int[] arr2 = new int[NEWSIZE];
for (int i = 0; i < arr1.Length; i++)
{ arr2[i] = arr1[i]; }
}
}
}
За допомогою вбудованого статичного методу Copy() класу System.Array зробити все набагато простіше та правильніше, як показано у наступному прикладі. Параметри методу Copy()наступні: вихідний масив; індекс вихідного масиву, з якого починається копіювання; масив, у який відбувається копіювання; індекс масиву-призначення у який відбудеться копіювання та кількість елементів для копіювання.
using System;
namespace LabDemo
{
class Program
{
static void Main(string[] args)
{
const int NEWSIZE = 10; // кількість елементів
int[] arr1 = { 1, 2, 3, 4, 5 };
// створюємо та ініціалізуємо новий масив
int[] arr2 = new int[NEWSIZE];
// копіюємо arr1.Length елементів масиву arr1 у масив
// arr2, починаючи з індексу 0
Array.Copy(arr1, 0, arr2, 0, arr1.Length);
}
}
}
Отже масив є найпростішою уже знайомою нам структурою даних. Крім масивів для організації різноманітних структур інформації в мові C# існують спеціальні класи об’єктів, що спрощують роботу із структурами даних зі змінною кількістю елементів. Для таких структур даних використовується термін «колекція» - це набір об’єктів, всі елементів якого можуть бути перебрані по черзі. Для ідентифікації кожного елементу використовується унікальне значення деякого ключа – у найпростішому випадку це може бути просто ціле число, власне, аналог індексу у масиві. Існують два основних підходи до організації структур даних: коли всі дані є довільними об’єктами (мають тип object – такі класи з’явились в .NET версії 1.1) та коли дані є типізованими (узагальнені колекції (Generic), що з’явились їм на зміну в версії .NET 2.0).
Нижче будуть розглянуті 4 типи структур даних:
-
Набір даних із цілими ключами
ArrayList – масив-список, елементи такої структури даних належать до типу object.
List<�Т> – типізований масив-список, всі елементи такої структури даних належать до типу Т.
-
Набір даних у вигляді пар значення-ключ із нецілими ключами
Hashtable – дані та ключі даних є довільними (належать до типу object)
Dictionary <�Т1,Т2> – дані та ключі є типізованими і належать до типів Т1 та Т2.
|