// интерфейса в дальнейшем использоваться не будет.

((IDrawToPrinter)oct).Draw();

// Также можно применять ключевое слово is.

if (oct is IDrawToMemory dtm)

{

  dtm.Draw();

}

Console.ReadLine();

Наряду с тем, что этот синтаксис действительно полезен, когда необходимо устранить конфликты имен, явную реализацию интерфейсов можно применять и просто для сокрытия более "сложных" членов на уровне объектов. В таком случае при использовании операции точки пользователь объекта будет видеть только подмножество всей функциональности типа. Однако когда требуется более сложное поведение, желаемый интерфейс можно извлекать через явное приведение.

<p id="AutBody_Root335">Проектирование иерархий интерфейсов</p>

Интерфейсы могут быть организованы в иерархии. Подобно иерархии классов, когда интерфейс расширяет существующий интерфейс, он наследует все абстрактные члены, определяемые родителем (или родителями). До выхода версии C# 8 производный интерфейс не наследовал действительную реализацию, а просто расширял собственное определение дополнительными абстрактными членами. В версии C# 8 производные интерфейсы наследуют стандартные реализации, а также расширяют свои определения и потенциально добавляют новые стандартные реализации.

Иерархии интерфейсов могут быть удобными, когда нужно расширить функциональность имеющегося интерфейса, не нарушая работу существующих кодовых баз. В целях иллюстрации создайте новый проект консольного приложения по имени InterfaceHierarchy. Затем спроектируйте новый набор интерфейсов, связанных с визуализацией, таким образом, чтобы IDrawable был корневым интерфейсом в дереве семейства:

namespace InterfaceHierarchy

{

  public interface IDrawable

  {

    void Draw();

  }

}

С учетом того, что интерфейс IDrawable определяет базовое поведение рисования, можно создать производный интерфейс, который расширяет IDrawable возможностью визуализации в других форматах, например:

namespace InterfaceHierarchy

{

  public interface IAdvancedDraw : IDrawable

  {

    void DrawInBoundingBox(int top, int left, int bottom, int right);

    void DrawUpsideDown();

  }

}

При таком проектном решении, если класс реализует интерфейс IAdvancedDraw, тогда ему потребуется реализовать все члены, определенные в цепочке наследования (в частности методы Draw(), DrawInBoundingBox() и DrawUpsideDown()):

using System;

namespace InterfaceHierarchy

{

  public class BitmapImage : IAdvancedDraw

  {

    public void Draw()

    {

      Console.WriteLine("Drawing...");

    }

    public void DrawInBoundingBox(int top, int left, int bottom, int right)

    {

      Console.WriteLine("Drawing in a box...");

    }

    public void DrawUpsideDown()

    {

      Console.WriteLine("Drawing upside down!");

    }

  }

}

Теперь в случае применения класса BitmapImage появилась возможность вызывать каждый метод на уровне объекта (из-за того, что все они открыты), а также извлекать ссылку на каждый поддерживаемый интерфейс явным образом через приведение:

using System;

using InterfaceHierarchy;

Console.WriteLine("***** Simple Interface Hierarchy *****");

// Вызвать на уровне объекта.

BitmapImage myBitmap = new BitmapImage();

myBitmap.Draw();

myBitmap.DrawInBoundingBox(10, 10, 100, 150);

myBitmap.DrawUpsideDown();

// Получить IAdvancedDraw явным образом.

if (myBitmap is IAdvancedDraw iAdvDraw)

{

  iAdvDraw.DrawUpsideDown();

}

Console.ReadLine();

<p id="AutBody_Root336">Иерархии интерфейсов со стандартными реализациями (нововведение в версии 8.0)</p>

Когда иерархии интерфейсов также включают стандартные реализации, то нижерасположенные интерфейсы могут задействовать реализацию из базового интерфейса или создать новую стандартную реализацию. Модифицируйте интерфейс IDrawable, как показано ниже:

public interface IDrawable

{

  void Draw();

  int TimeToDraw() => 5;

}

Теперь обновите операторы верхнего уровня:

Перейти на страницу:

Похожие книги