Прошел курс. Получил код 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 . Снижение статуса ссылки для адресации к тонким слоям составного объекта
Очень важно, что компилятор принципиально не пропускает в функцию объект, который имеет тип тоньше ожидаемого, поскольку для корректной работы внутри функции переданной информации может быть недостаточно. В то же время, внутри функции мы можем адресоваться к более тонким слоям объекта, надеясь, что компилятор следит за тем, чтобы в функцию были переданы все части ожидаемого объекта. А ожидается именно заявленный в параметрах толстый объект, или еще более толстый его наследник.
Результат работы программы будет такой