Вот код, иллюстрирующий особенности применения операций is и as.
using System;
namespace derivation01
{
// Базовый класс...
class X
{//_____________________________.
public int f1(int key)
{
Console.WriteLine("X.f1");
return key;
}
}//_____________________________.
// Производный...
class Y:X
{//_____________________________.
new public int f1(int key)
{
Console.WriteLine("Y.f1");
base.f1(key);
return key;
}
public int yf1(int key)
{
Console.WriteLine("Y.yf1");
return key;
}
}//_____________________________.
// Производный...
class Z:X
{//_____________________________.
public int zf1(int key)
{
Console.WriteLine("Z.zf1");
return key;
}
}//_____________________________.
class Class1
{
static void Main(string[] args)
{
int i;
// Всего лишь ссылки на объекты...
X x;
Y y;
Z z;
Random rnd = new Random();
// И вот такой тестовый пример позволяет выявить особенности применения
// операций is и as.
for (i = 0; i < 10; i++)
{//=================================================================================.
// Ссылка на объект базового класса случайным образом
// настраивается на объекты производного класса.
if (rnd.Next(0,2) == 1)
x = new Y();
else
x = new Z();
// Вызов метода f1 не вызывает проблем.
// Метод базового класса имеется у каждого объекта.
x.f1(0);
// А вот вызвать метод, объявленный в производном классе
// (с использованием операции явного приведения типа)
// удаётся не всегда. Метод yf1 был объявлен лишь в классе Y.
// Ниже операция is принимает значение true лишь в том случае,
// если ссылка на объект базового класса была настроена на объект класса Y.
if (x is Y)
{
((Y)x).yf1 (0); // И только в этом случае можно вызвать метод,
// объявленный в Y.
}
else
{
((Z)x).zf1 (1); // А в противном случае попытка вызова yf1
// привела бы к катастрофе.
try
{
((Y)x).yf1 (0);
}
catch (Exception ex)
{
Console.WriteLine("-1-" + ex.ToString());
}
}
// А теперь объект, адресуемый ссылкой на базовый класс надо попытаться
// ПРАВИЛЬНО переадресовать на ссылку соответствующего типа. И это тоже
// удаётся сделать не всегда. Явное приведение может вызвать исключение.
try
{
z = (Z)x;
}
catch (Exception ex)
{
Console.WriteLine("-2-" + ex.ToString());
}
try
{
y = (Y)x;
}
catch (Exception ex)
{
Console.WriteLine("-3-" + ex.ToString());
}
// Здесь помогает операция as.
// В случае невозможности переадресации соответствующая ссылка оказывается
// установленной в null. А эту проверку выполнить проще...
if (rnd.Next(0,2) == 1)
{
z = x as Z;
if (z != null) z.zf1(2);
else Console.WriteLine("?????");
}
else
{
y = x as Y;
if (y != null) y.yf1(3);
else Console.WriteLine("!!!!!");
}
}//=================================================================================.
}
}
}