|
Прошел курс. Получил код Dreamspark. Ввожу код на сайте, пишет: Срок действия этого кода проверки уже истек. Проверьте, правильно ли введен код. У вас осталось две попытки. Вы также можете выбрать другой способ проверки или предоставить соответствующие документы, подтверждающие ваш академический статус.
Как активировать код? |
Наследование в C#
Функция ждет тонкий объект
Такие свойства преобразования типов очень часто применяются в функциях. Если в качестве параметра функции используется ссылка на объект базового типа, то в качестве аргумента может быть передан объект любого родственного производного типа. Внутри же функции, чтобы использовать доступ к членам переданного объекта, нужно повысить статус ссылки базового типа до уровня типа переданного объекта.
Чтобы проиллюстрировать использование ссылок базового типа в параметрах функции, заменим в предыдущем примере класс MyClass следующей модификацией (весь остальной код предыдущего примера остается неизменным)
// Вызывающая сторона
class MyClass
{
public MyClass()
{
// Создаем объекты для всех типов
// иерархической цепочки наследования
Point point = new Point(1, 2);
Circle circle = new Circle(3, 4, 5);
Cylinder cylinder = new Cylinder(6, 7, 8, 9);
// Последовательно препарируем объекты
Console.WriteLine("Анализируется
объект Point(1, 2)");
PrepareObject(point);
Console.WriteLine("\n\nАнализируется
объект Circle(3, 4, 5)");
PrepareObject(circle);
Console.WriteLine("\n\nАнализируется
объект Cylinder(6, 7, 8, 9)");
PrepareObject(cylinder);
}
void PrepareObject(Point ob)// Функция ожидает базовый тип, поэтому
// ей можно передавать объекты любого производного типа
{
Console.WriteLine("Слой типа Point");
ob.Show(); // Всегда есть в переданном
// Безопасно проверяем, чтобы не
//адресоваться к несуществующему слою
// Проверяем существование слоя Circle одним способом
if (ob is Circle)// Выражение равно true, если слой есть
{
Console.WriteLine("\nСлой типа Circle");
Circle circle = (Circle)ob;// Повышаем полномочия ссылки ob
circle.Show();
Console.WriteLine("Длина окружности: {0}",
circle.Length());
Console.WriteLine("Площадь круга: {0}",
circle.Area());
}
// Проверяем существование слоя Cylinder другим способом
Cylinder cylinder = ob as Cylinder;
// Ссылка нулевая, если слоя нет
if (cylinder != null)
{
Console.WriteLine("\nСлой типа Cylinder");
((Cylinder)ob).Show();
// Повышаем полномочия ссылки ob налету
Console.WriteLine("Площадь всей поверхности:
{0}", cylinder.Area());
Console.WriteLine("Объем: {0}",
cylinder.Volume());
}
}
}
Листинг
9.11 .
Использование базовых ссылок в параметрах функций
Результат выполнения программы с модифицированным классом MyClass следующий
Чтобы не вызвать исключение времени выполнения при попытке адресации к несуществующему слою переданного объекта, мы внутри функции вначале проверяем наличие этого слоя в адресуемом объекте. Для этого используются равноценные конструкции языка с ключевыми словами as и is.
В пределе тип ссылки в аргументе функции можно объявить как object (или Object ), поскольку класс Object является базовым для всех типов без исключения. Но в этом случае внутри функции ссылку на объект Point также нужно привести к типу Point и начало функции выглядело бы так
void PrepareObject(object ob)// Функция ожидает самый базовый тип, поэтому
// ей можно передавать объекты любого типа
{
Console.WriteLine("Слой типа Point");
((Point)ob).Show(); // Теперь тоже нужно приводить
...........Остальное без изменений...........
}
Листинг
9.12 .
Использование абсолютно базового типа
Таким образом, когда функция ожидает поступления одного из родственных объектов, связанных цепочкой наследования, но не знает, какого именно родственника ей передаст вызывающий код, правильнее всего указать в качестве аргумента тип самого базового родственника, способного представлять любого наследника. А затем уже внутри функции безопасно проверять, к какому типу принадлежит фактически поступивший родственник.
В этом и заключается динамический полиморфизм базовых ссылок, когда одна и та же ссылка может адресовать множество родственных объектов. И все это на этапе выполнения. Нужно только привести заполненную адресом конкретного объекта базовую ссылку к фактическому типу этого объекта.
Функция ждет толстый объект
Статус ссылки на родственные объекты можно не только повышать, но и снижать для адресации к тонким слоям объекта. Вот новая модификация класса MyClass нашего примера
// Вызывающая сторона
class MyClass
{
public MyClass()
{
// Создаем многослойный толстый объект
Cylinder cylinder = new Cylinder(6, 7, 8, 9);
// Передаем объект функции для послойной препарации
PrepareObject(cylinder);
// Тонкие объекты передавать нельзя,
// когда функция ожидает толстый объект,
// поскольку функция может потребовать
// от них несуществующих возможностей
// PrepareObject((Circle)cylinder);// Ошибка компиляции!!!
// PrepareObject((Point)cylinder); // Ошибка компиляции!!!
}
void PrepareObject(Cylinder ob)// Функция ожидает толстый тип
{
// Проверяем, что это именно толстый тип
// if (ob is Cylinder)
// {
// ...
// }
// Проверять необязательно, поскольку тоньше объекта,
// чем ожидается, компилятор не пропустит, а если будет
// передан более толстый объект, мы его приведем к исходному
Cylinder cylinder = (Cylinder)ob;
// На случай, если передадут толще
// Заготавливаем адреса разных слоев составного объекта,
// снижая тем самым статус ссылки на исходный объект
Point point = (Point)ob;
Circle circle = (Circle)ob;
// Адресуемся к членам слоя Point
Console.WriteLine("Слой типа Point");
point.Show();
// Адресуемся к членам слоя Circle
Console.WriteLine("\nСлой типа Circle");
circle.Show();
Console.WriteLine("Длина окружности: {0}",
circle.Length());
Console.WriteLine("Площадь круга: {0}",
circle.Area());
// Адресуемся к членам слоя Cylinder
Console.WriteLine("\nСлой типа Cylinder");
cylinder.Show();
Console.WriteLine("Площадь всей поверхности: {0}",
cylinder.Area());
Console.WriteLine("Объем: {0}",
cylinder.Volume());
}
}
Листинг
9.13 .
Снижение статуса ссылки для адресации к тонким слоям составного объекта
Очень важно, что компилятор принципиально не пропускает в функцию объект, который имеет тип тоньше ожидаемого, поскольку для корректной работы внутри функции переданной информации может быть недостаточно. В то же время, внутри функции мы можем адресоваться к более тонким слоям объекта, надеясь, что компилятор следит за тем, чтобы в функцию были переданы все части ожидаемого объекта. А ожидается именно заявленный в параметрах толстый объект, или еще более толстый его наследник.
Результат работы программы будет такой

