В оставшихся главах книги вы встретите десятки интерфейсов, поставляемых в библиотеках базовых классов .NET Core. Вы увидите, что эти интерфейсы могут быть реализованы в собственных специальных классах и структурах для определения типов, которые тесно интегрированы с платформой. Вдобавок, как только вы оцените полезность интерфейсных типов, вы определенно найдете причины для построения собственных таких типов.
Сравнение интерфейсных типов и абстрактных базовых классов
Учитывая материалы главы 6, интерфейсный тип может выглядеть кое в чем похожим на абстрактный базовый класс. Вспомните, что когда класс помечен как абстрактный, он
Полиморфный интерфейс, устанавливаемый абстрактным родительским классом, обладает одним серьезным ограничением: члены, определенные абстрактным родительским классом, поддерживаются System.Object. Учитывая, что абстрактные члены в абстрактном базовом классе применимы только к производным типам, не существует какого-то способа конфигурирования типов в разных иерархиях для поддержки одного и того же полиморфного интерфейса. Для начала создайте новый проект консольного приложения по имени СиstomInterfaces. Добавьте к проекту следующий абстрактный класс:
namespace CustomInterfaces
{
public abstract class CloneableType
{
// Поддерживать этот "полиморфный интерфейс".
// могут только производные типы.
// Классы в других иерархиях не имеют доступа
// к данному абстрактному члену
public abstract object Clone();
}
}
При таком определении поддерживать метод Clone() способны только классы, расширяющие CloneableType. Если создается новый набор классов, которые не расширяют данный базовый класс, то извлечь пользу от такого полиморфного интерфейса не удастся. К тому же вы можете вспомнить, что язык C# не поддерживает множественное наследование для классов. По этой причине, если вы хотите создать класс MiniVan, который является и Car, и CloneableType, то поступить так, как показано ниже, не удастся:
// Недопустимо! Множественное наследование для классов в C# невозможно
public class MiniVan : Car, CloneableType
{
}
Несложно догадаться, что на помощь здесь приходят интерфейсные типы. После того как интерфейс определен, он может быть реализован любым классом либо структурой, в любой иерархии и внутри любого пространства имен или сборки (написанной на любом языке программирования .NET Core). Как видите, интерфейсы являются ICloneable, определенный в пространстве имен System. В нем определен единственный метод по имени Clone():
public interface ICloneable
{
object Clone();
}
Во время исследования библиотек базовых классов .NET Core вы обнаружите, что интерфейс ICloneable реализован очень многими на вид несвязанными типами (System.Array, System.Data.SqlClient.SqlConnection, System.OperatingSystem, System.String и т.д.). Хотя указанные типы не имеют общего родителя (кроме System.Object), их можно обрабатывать полиморфным образом посредством интерфейсного типа ICloneable. Первым делом поместите в файл Program.cs следующий код:
using System;
using CustomInterfaces;
Console.WriteLine("***** A First Look at Interfaces *****\n");
CloneableExample();