Рейтинговые книги
Читем онлайн Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 103 104 105 106 107 108 109 110 111 ... 407
структурированной обработки исключений. Когда методу необходимо отправить объект ошибки вызывающему коду, он должен создать, сконфигурировать и сгенерировать специфичный объект производного от System.Exception типа посредством ключевого слова throw языка С#. Вызывающий код может обрабатывать любые входные исключения с применением ключевого слова catch и необязательного блока finally. В версии C# 6 появилась возможность создавать фильтры исключений с использованием дополнительного ключевого слова when, а в версии C# 7 расширен перечень мест, где можно генерировать исключения.

Когда вы строите собственные специальные исключения, то в конечном итоге создаете класс, производный от класса System.ApplicationException, который обозначает исключение, генерируемое текущим выполняющимся приложением. В противоположность этому объекты ошибок, производные от класса System.SystemException, представляют критические (и фатальные) ошибки, генерируемые исполняющей средой .NET 5. Наконец, в главе были продемонстрированы разнообразные инструменты среды Visual Studio, которые можно применять для создания специальных исключений (согласно установившейся практике .NET), а также для отладки необработанных исключений. 

Глава 8

Работа с интерфейсами

Материал настоящей главы опирается на ваши текущие знания объектно-ориентированной разработки и посвящен теме программирования на основе интерфейсов. Вы узнаете, как определять и реализовывать интерфейсы, а также ознакомитесь с преимуществами построения типов, которые поддерживают несколько линий поведения. В ходе изложения обсуждаются связанные темы, такие как получение ссылок на интерфейсы, явная реализация интерфейсов и построение иерархий интерфейсов. Будет исследовано несколько стандартных интерфейсов, определенных внутри библиотек базовых классов .NET Core. Кроме того, раскрываются новые средства C# 8, связанные с интерфейсами, в том числе стандартные методы интерфейсов, статические члены и модификаторы доступа. Вы увидите, что специальные классы и структуры могут реализовывать эти предопределенные интерфейсы для поддержки ряда полезных аспектов поведения, включая клонирование, перечисление и сортировку объектов.

Понятие интерфейсных типов

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

Средство стандартных методов интерфейсов, введенное в C# 8.0, позволяет методам интерфейса содержать реализацию, которая может переопределяться или не переопределяться в классе реализации. Более подробно о таком средстве речь пойдет позже в главе.

Как вы наверняка догадались, библиотеки базовых классов .NET Core поставляются с многочисленными предопределенными интерфейсными типами, которые реализуются разнообразными классами и структурами. Например, в главе 21 будет показано, что инфраструктура ADO.NET содержит множество поставщиков данных, которые позволяют взаимодействовать с определенной системой управления базами данных. Таким образом, в ADO.NET на выбор доступен обширный набор классов подключений (SqlConnection, OleDbConnection, OdbcConnection и т.д.). Вдобавок независимые поставщики баз данных (а также многие проекты с открытым кодом) предлагают библиотеки .NET Core для взаимодействия с большим числом других баз данных (MySQL, Oracle и т.д.), которые содержат объекты, реализующие упомянутые интерфейсы.

Невзирая на тот факт, что каждый класс подключения имеет уникальное имя, определен в отдельном пространстве имен и (в некоторых случаях) упакован в отдельную сборку, все они реализуют общий интерфейс под названием IDbConnection:

// Интерфейс IDbConnection определяет общий набор членов,

// поддерживаемый всеми классами подключения.

public interface IDbConnection : IDisposable

{

   // Методы

   IDbTransaction BeginTransaction();

   IDbTransaction BeginTransaction(IsolationLevel il);

   void ChangeDatabase(string databaseName);

   void Close();

   IDbCommand CreateCommand();

   void Open();

   // Свойства

   string ConnectionString { get; set;}

   int ConnectionTimeout { get; }

   string Database { get; }

   ConnectionState State { get; }

}

На заметку! По соглашению имена интерфейсов .NET снабжаются префиксом в виде заглавной буквы I. При создании собственных интерфейсов рекомендуется также следовать этому соглашению.

В настоящий момент детали того, что делают члены интерфейса IDbConnection, не важны. Просто запомните, что в IDbConnection определен набор членов, которые являются общими для всех классов подключений ADO.NET. В итоге каждый класс подключения гарантированно поддерживает такие члены, как Open(), Close(), CreateCommand() и т.д. Кроме того, поскольку методы интерфейса IDbConnection всегда абстрактные, в каждом классе подключения они могут быть реализованы уникальным образом.

В оставшихся главах книги вы встретите десятки интерфейсов, поставляемых в библиотеках базовых классов .NET Core. Вы увидите, что эти интерфейсы могут быть реализованы в собственных специальных классах и структурах для определения типов, которые тесно интегрированы с платформой. Вдобавок, как только вы оцените полезность интерфейсных типов, вы определенно найдете причины для построения собственных таких типов.

Сравнение интерфейсных типов и абстрактных базовых классов

Учитывая материалы главы 6, интерфейсный тип может выглядеть кое в чем похожим на абстрактный базовый класс. Вспомните, что когда класс помечен как абстрактный, он может определять любое количество абстрактных членов для предоставления полиморфного интерфейса всем производным типам. Однако даже если класс действительно определяет набор абстрактных членов, он также может определять любое количество конструкторов, полей данных, неабстрактных членов (с реализацией) и т.д. Интерфейсы (до C# 8.0) содержат только определения членов. Начиная с версии C# 8, интерфейсы способны содержать определения членов (вроде абстрактных членов), члены со стандартными реализациями (наподобие виртуальных членов) и статические члены. Есть только два реальных отличия: интерфейсы не могут иметь нестатические конструкторы, а класс может реализовывать множество интерфейсов. Второй аспект обсуждается следующим.

Полиморфный интерфейс, устанавливаемый абстрактным родительским классом, обладает одним серьезным ограничением: члены, определенные абстрактным родительским классом, поддерживаются только производными типами. Тем не менее, в крупных программных системах часто разрабатываются многочисленные иерархии классов, не имеющие общего родителя кроме System.Object. Учитывая, что абстрактные члены в абстрактном базовом классе применимы только к производным типам, не существует какого-то способа конфигурирования типов в разных иерархиях для поддержки одного и того же полиморфного интерфейса. Для начала создайте новый проект консольного приложения по имени СиstomInterfaces. Добавьте к проекту следующий абстрактный класс:

namespace CustomInterfaces

{

  public abstract class CloneableType

1 ... 103 104 105 106 107 108 109 110 111 ... 407
На этой странице вы можете бесплатно читать книгу Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен бесплатно.

Оставить комментарий