
- •Ключове слово this
- •Ключове слово static
- •Статичний конструктор
- •Інкапсуляція з використанням методів get і set
- •Інкапсуляція з використанням властивостей
- •Організація робіт при описі класу. Атрибут partial
- •Спадкоємство
- •Int point; // поле
- •Додавання до класу запечатаного класу
- •Вкладеність класів
- •Поліморфізм
- •Абстрактні класи
- •Приховування членів класу
- •Оператори as і is
- •Структури
Оператори as і is
Через те що object є загальним базовим типом, будь-яке посилання на клас можна перетворити в посилання на object, а посилання на object можна спробувати перетворити в посилання на будь-який клас. Слово «спробувати» сказано не випадково, тому що явне перетворення (з нащадка в батька) проходить не завжди, бо нащадок - це розширення батька. Приведення "вниз" завжди виконується явно. Існують спеціальні оператори, які визначають сумісність типів. Це оператори з ключовими словами as та is. Вони працюють на сумісність не тільки таких складних типів, як класи, але і для базових типів, таких як, наприклад, int. Як працює оператор is, видно з прикладу, приведеного в лістингу 8.15.
Лістинг 8.15
using System;
namespace app33_as_and_is
{
public class test
{
static void Main()
{
String derived_obj = "Dummy"; // Похідний об'єкт класу String (із статичних
// класів екземпляри не створюються)
Object base_objl = new Object (); // Базовий об'єкт
Object base_obj2 = derived_obj; // Явне перетворення: запам'ятовування
// посилання в базовому об'єкті
Console.WriteLine ("base_obj2 {0} String", base_obj2 is String ? "є" : "не є");
Console.WriteLine ("base_objl {0} String", base_objl is String ? "є" : "не є");
Console.WriteLine ("derived_obj {0} Object", derived_obj is Object ? "є" : "не є");
int j = 123;
object b = j;
object obj = new Object () ;
Console.WriteLine ("b {0} int", b is int ? "є" : "не є");
Console.WriteLine ("obj {0} int", obj is int ? "є" : "не є");
Console.WriteLine("b {0} System.ValueType", b is ValueType ? "є" : "не є");
float f=12.3f;
Console.WriteLine ("f {0} int", f is int ? "є" : "не є");
Console.Read();
}
}
}
Результат роботи програми представлений на рис. 8.12.
Рис. 8.12. Перевірка роботи оператора is
У програмі створюється екземпляр класу String. Це системний статичний клас. З таких класів екземпляри не створюються, тому змінній цього типу derived_Obj здійснюється присвоєння значення безпосередньо. Вважатимемо, що це - похідний клас, бо всі класи, в тому числі і String, походять від загального батька - класу Object. Його і почнемо вважати батьком. Його екземпляри - base_Obj1 і base_Obj2. В останньому запам'ятовується посилання на похідний клас derived_Obj. А далі йдуть перевірки за допомогою оператора is на сумісність типів. Перевірка здійснюється всередині оператора Console.WriteLine(), у якому як вираз, що виводиться на екран, служить вираз вигляду base_Obj2 is String ? "є" : "не є". Такий оператора ми ще не зустрічали. Його позначення – знак питання (?). Він називається тернарним (з трьох частин) умовним оператором на відміну від бінарного (з двох частин) умовного оператора if...else. Загальна форма такого оператора:
Вираз1 ? Вираз2 : Вираз3;
Тут Вираз1 повинен відноситися до типу bool (тут і задається умова), а Вираз2 і Вираз3 - до одного і того ж типу. Зверніть увагу на застосування двокрапки і її місцеположення в операторі ?. Результат визначається таким чином. Спочатку обчислюється Вираз1. Якщо воно істинне (True), то обчислюється Вираз2, і отриманий результат - результат всього оператора. Якщо ж Вираз1 виявляється помилковим (значення - False), то обчислюється Вираз3, і його значення стає загальним результатом.
У нас в програмі записано
base_Obj2 is String ? "є" : "не є"
Тобто Вираз1 - це base_Obj2 is String (перевірка: чи є base_Obj2 типом String). Цей вираз можна було б в програмі записати у вигляді
bool b1= base_Obj2 is String;
Тоді вираз
base_Obj2 is String ? "є" : "не є"
був би таким:
b1 ? "є" : "не є"
У результаті оператор
Console.WriteLine("base_Obj2 {0} String", b1 ? "є" : "не є");
працює так: виводиться base_Obj2 (те, що не відноситься до формату, виводиться один до одного), потім обробляється формат, тобто вибирається для виведення із списку аргументів перший (він у нас єдиний). Це якраз тернарний умовний оператор-вираз. Він обчислюється і виводиться. Після цього за форматом {0} знову йдуть не форматні символи (String). Вони виводяться на екран без зміни.
Приклад роботи з оператором is показаний в програмі, приведеній у лістингу 8.16. Результат її роботи представлений на рис. 8.13.
Лістинг 8.16
using System;
namespace App33_as_and_is2
{
public class BaseType { }
public class DerivedType : BaseType { }
public class Program
{
static void Main()
{
Console.WriteLine("Перевірка оператора as");
DerivedType derived_Obj = new DerivedType(); // об'єкт похідного класу
BaseType base_Objl = new BaseType(); // Об'єкт базового класу
BaseType base_Obj2 = derived_Obj; // Неявне перетворення в базовий клас
// Перевірка, чи є базовий тип після перетворення в нього похідного
// похідним типом. Якщо ні, то результатом as буде посилання null
DerivedType derived_Obj2 = base_Obj2 as DerivedType;
if (derived_Obj2 != null)
{
Console.WriteLine("Похідний тип " + "перетворився в базовий вдало");
}
else
{
Console.WriteLine("Перетворення похідного " + "типу в базовий не вдале");
}
// Перевірка: чи є базовий тип похідним
derived_Obj2 = base_Objl as DerivedType;
if (derived_Obj2 != null)
{
Console.WriteLine("Базовий тип перетворився " + "в похідний вдало");
}
else
{
Console.WriteLine("Перетворення базового типу " + "у похідний не вдале");
}
// Перевірка: чи є похідний тип базовим
BaseType base_Obj3 = derived_Obj as BaseType;
if (base_Obj3 != null)
{
Console.WriteLine("Похідний тип сумісний " + "з базовим");
}
else
{
Console.WriteLine("Похідний тип не сумісний " + "з базовим");
}
Console.Read();
}
}
}
Оператор as на відміну від is при несумісності типів видає значення null.
Рис. 8.13. Перевірка роботи оператора as