Язык программирования C#9 и платформа .NET5
using System;using InterfaceHierarchy;Console.WriteLine("***** Simple Interface Hierarchy *****");<b>// Вызвать на уровне объекта.</b>BitmapImage myBitmap = new BitmapImage();myBitmap.Draw();myBitmap.DrawInBoundingBox(10, 10, 100, 150);myBitmap.DrawUpsideDown();<b>// Получить IAdvancedDraw явным образом.</b>if (myBitmap is IAdvancedDraw iAdvDraw){iAdvDraw.DrawUpsideDown();}Console.ReadLine();Иерархии интерфейсов со стандартными реализациями (нововведение в версии 8.0)
Когда иерархии интерфейсов также включают стандартные реализации, то нижерасположенные интерфейсы могут задействовать реализацию из базового интерфейса или создать новую стандартную реализацию. Модифицируйте интерфейс
, как показано ниже:IDrawablepublic interface IDrawable{void Draw();int TimeToDraw() => 5;}Теперь обновите операторы верхнего уровня:
Console.WriteLine("***** Simple Interface Hierarchy *****");...if (myBitmap is IAdvancedDraw iAdvDraw){iAdvDraw.DrawUpsideDown();Console.WriteLine($"Time to draw: {iAdvDraw.TimeToDraw()}");}Console.ReadLine();Этот код не только скомпилируется, но и выведет значение
при вызове метода5. Дело в том, что стандартные реализации попадают в производные интерфейсы автоматически. ПриведениеTimeToDraw()к интерфейсуBitMapImageобеспечивает доступ к методуIAdvancedDraw, хотя экземплярTimeToDraw()не имеет доступа к стандартной реализации. Чтобы удостовериться в этом, введите следующий код, который вызовет ошибку на этапе компиляции:BitMapImage// Этот код не скомпилируетсяmyBitmap.TimeToDraw();Если в нижерасположенном интерфейсе желательно предоставить собственную стандартную реализацию, тогда потребуется скрыть вышерасположенную реализацию. Например, если вычерчивание в методе
изTimeToDraw()занимает 15 единиц времени, то модифицируйте определение интерфейса следующим образом:IAdvancedDrawpublic interface IAdvancedDraw : IDrawable{void DrawInBoundingBox(int top, int left, int bottom, int right);void DrawUpsideDown();<b> new int TimeToDraw() => 15;</b>}Разумеется, в классе
также можно реализовать методBitMapImage. В отличие от методаTimeToDraw()изTimeToDraw()в классе необходимо только реализовать метод без его сокрытия.IAdvancedDrawpublic class BitmapImage : IAdvancedDraw{...public int TimeToDraw() => 12;}В случае приведения экземпляра
к интерфейсуBitmapImageилиIAdvancedDrawметод на экземпляре по-прежнему выполняется. Добавьте к операторам верхнего уровня показанный далее код:IDrawable// Всегда вызывается метод на экземпляре:Console.WriteLine("***** Calling Implemented TimeToDraw *****");Console.WriteLine($"Time to draw: {myBitmap.TimeToDraw()}");Console.WriteLine($"Time to draw: {((IDrawable) myBitmap).TimeToDraw()}");Console.WriteLine($"Time to draw: {((IAdvancedDraw) myBitmap).TimeToDraw()}");Вот результаты:
***** Simple Interface Hierarchy *****...***** Calling Implemented TimeToDraw *****Time to draw: 12Time to draw: 12Time to draw: 12Множественное наследование с помощью интерфейсных типов
В отличие от типов классов интерфейс может расширять множество базовых интерфейсов, что позволяет проектировать мощные и гибкие абстракции. Создайте новый проект консольного приложения по имени
. Здесь имеется еще одна коллекция интерфейсов, которые моделируют разнообразные абстракции, связанные с визуализацией и фигурами. Обратите внимание, что интерфейсMiInterfaceHierarchyрасширяет иIShape, иIDrawable:IPrintable// IDrawable.csnamespace MiInterfaceHierarchy{// Множественное наследование для интерфейсных типов - это нормально.interface IDrawable{