Даний уро к є продовженням попереднього, присвяченого спадкоємцям.
У Сі-шарп є можливість створення масиву (або списку) вказівників на базовий клас в якому в якості елементів можуть бути об'єкти класу-спадкоємця. Наприклад, ми можемо створити масив об'єктів Тварина, і елементами такого масиву будуть об'єкти класів Собака, Кішка.
Приклад:
class Animal
{
public string Name {get; set; }
public Animal (string name)
{
Name = name;
}
}
class Dog: Animal
{
public Dog (string name): base (name)
{}
public void Guard ()
{
// Собака охороняє
}
}
class Cat: Animal
{
public Cat (string name): base (name)
{}
public void CatchMouse ()
{
// Кішка ловить миша
}
}
class Program
{
static void Main (string [] args)
{
List <Animal> animals = new List <Animal> (); // Створюємо список покажчиків на базовий клас
animals.Add (new Dog ("Барбос"));
animals.Add (new Cat ("Барсік"));
animals.Add (new Dog ("Полкан"));
foreach (Animal animal in animals)
{
Console.WriteLine (animal.Name);
}
Console.ReadLine ();
}
}
Хоча як елементи в цей список ми додавали об'єкти класів-спадкоємців Собака і Кішка, будучи елементами списку покажчиків на базовий клас, ці об'єкти перетворюються до об'єктів базового класу, і ми маємо доступ тільки до тієї частини об'єктів, яка описана в базовому класі - ми не можемо тут викликати методи Guard () або CatchMouse (), але при цьому маємо доступ до імені тварини.
Зворотне тут неможливо. Не можна створити масив об'єктів класу Собака, і записати в нього об'єкти класу Тварина.
Оператор is
Оператор is працює дуже просто - він перевіряє сумісність об'єкта з вказаним типом (належить об'єкт певного класу). Оператор is повертає істину (true), якщо об'єкт належить класу. Істинна буде також при перевірці сумісності об'єкта класу-спадкоємця і базового класу:
static void Main (string [] args)
{
Dog dog1 = new Dog ("Барбос");
Console.WriteLine (dog1 is Dog); // True
Console.WriteLine (dog1 is Animal); // True
Console.WriteLine (dog1 is Cat); // False
Console.ReadLine ();
}
Користуючись оператором is і явним перетворенням, тепер ми можемо повноцінно використовувати масив покажчиків на базовий клас:
class Animal
{
public string Name {get; set; }
public Animal (string name)
{
Name = name;
}
}
class Dog: Animal
{
public Dog (string name): base (name)
{}
public void Guard ()
{
Console.WriteLine (Name + "охороняє");
}
}
class Cat: Animal
{
public Cat (string name): base (name)
{}
public void CatchMouse ()
{
Console.WriteLine (Name + "ловить миша");
}
}
class Program
{
static void Main (string [] args)
{
List <Animal> animals = new List <Animal> ();
animals.Add (new Dog ("Барбос"));
animals.Add (new Cat ("Барсік"));
animals.Add (new Dog ("Полкан"));
foreach (Animal animal in animals)
{
if (animal is Dog) // перевіряємо чи є дане тварина собакою
((Dog) animal) .Guard ();
else ((Cat) animal) .CatchMouse ();
}
Console.ReadLine ();
}
}
Тут, використавши явне перетворення, ми отримуємо повний доступ до об'єктів зі списку, і можемо викликати методи Guard () і CatchMouse ().
Оператор as
У прикладі вище, замість явного приведення типів можна було використовувати оператор as. (Dog) animal еквівалентно висловом animal as Dog. Різниця між оператором as і явним приведенням лише в тому, що у разі неможливості перетворення, оператор as повертає null, тоді як явне приведення викидає виключення. Приклад програми вище, тільки вже з оператором as:
class Program
{
static void Main (string [] args)
{
List <Animal> animals = new List <Animal> ();
animals.Add (new Dog ("Барбос"));
animals.Add (new Cat ("Барсік"));
animals.Add (new Dog ("Полкан"));
foreach (Animal animal in animals)
{
if (animal is Dog) // перевіряємо чи є дане тварина собакою
(animal as Dog) .Guard ();
else (animal as Cat) .CatchMouse ();
}
Console.ReadLine ();
}
}