C#: Абстрактные классы и интерфейсы
Иногда мы хотим создавать классы, которые должны быть просто эскизом для некоторых более специализированных реализаций. Это похоже на создание шаблона для классов. Мы не хотим использовать шаблон напрямую, но мы хотим получить его из класса, что должно сэкономить нам некоторое время. Ключевое слово для маркировки класса, который является шаблоном -
abstract
. Нельзя создать экземпляр абстрактного класса. В таком классе, все поля и методы также отмечаются ключевым словом abstract
. Для реализации такого класса потребуются производные классы:Скрыть код копирования
abstract class MyClass
{
public abstract void Write(string name);
}
class MySubClass : MyClass
{
public override void Write(string name)
{
Console.WriteLine("Hi {0} from an implementation of Write!", name);
}
}
Здесь мы отмечаем
Write
метод как абстрактный, что имеет два следствия:- В первом определении метода нет тела метода (в фигурных скобках отсутствует).
В классе
MySubClass
требуется написать ключевое словоoverride
перед методом
Write.
Кроме того, следующий код не сработает, поскольку мы создаем экземпляр
MyClass
, который теперь помечен как абстрактный.//Ouch, MyClass is abstract!
MyClass a = new MyClass();
//This works fine, MyClass can still be used as a type
MyClass b = new MySubClass();
Важным ограничением ОПП в C# является ограничение наследования, мы можем насоедоваться только от одного класса. Если мы не укажем базовый класс, то
Object
будем использовать неявно, иначе будет использоваться явно определенный класс. Элегантный способ обхода этого ограничения, основан на использовании так называемых interface
типов.Интерфейсы определяют, какие функции должны предоставляться классам или структурам, которые их реализуют, но они не говорят ни слова о том, как выглядит точная функция. При этом мы можем рассматривать эти интерфейсы как абстрактные классы без переменных и только с
abstract
членами (методы, свойства, ...).Давайте определим очень простой интерфейс:
Скрыть код копирования
interface MyInterface
{
void DoSomething();
string GetSomething(int number);
}
Определенный нами интерфейс содержит всего лишь два метода, которые названы
DoSomething
и GetSomething соответственно
. Определения этих методов очень похожи на определения абстрактных методов, за исключением того, что нам не хватает ключевых слов public
и abstract
. Это по дизайну. Идея состоит в том, что, поскольку каждый член интерфейса abstract
(или, точнее говоря, пропускает реализацию), ключевое слово является избыточным. Другая особенность заключается в том, что каждый метод автоматически обрабатывается как public
.Внедрение интерфейса возможно с использованием того же синтаксиса, что и для классов. Рассмотрим два примера:
class MyOtherClass : MyInterface
{
public void DoSomething()
{ }
public string GetSomething(int number)
{
return number.ToString();
}
}
class MySubSubClass : MySubClass, MyInterface
{
public void DoSomething()
{ }
public string GetSomething(int number)
{
return number.ToString();
}
}
Этот фрагмент должен продемонстрировать несколько вещей:
- Можно реализовать только один интерфейс и класс (это приведет к прямому наследованию
Object
) - Мы также можем реализовать один или несколько интерфейсов и дополнительно класс (явное наследование)
- Нам всегда нужно реализовать все методы «унаследованного» интерфейса (ов)
- Кроме того, в качестве дополнительной заметки нам не нужно повторно внедрять
Write
метод вMySubSubClass
, посколькуMySubClass
уже реализует его
Должно быть ясно, что мы не можем создавать интерфейсы (они похожи на абстрактные классы), но мы можем использовать их как типы. Поэтому можно было бы сделать следующее:
MyInterface myif = new MySubSubClass();
Обычно типы интерфейсов начинаются с большого I в .NET-Framework. Это полезное соглашение для немедленного распознавания интерфейсов. В нашем путешествии мы найдем некоторые полезные интерфейсы, которые очень важны для .NET-Framework. Некоторые из этих интерфейсов используются C # неявно.
Интерфейсы также дают нам еще один вариант для реализации их методов. Поскольку мы можем реализовать несколько интерфейсов, возможно, что будут включены два метода с тем же именем и сигнатурой. В этом случае должен быть способ различать различные реализации. Это возможно благодаря так называемой явной реализации. Явный интерфейс не будет вносить вклад в класс напрямую. Вместо этого нужно передать класс конкретному типу интерфейса, чтобы получить доступ к членам интерфейса.
Вот явная реализация:
class MySubSubClass : MySubClass, MyInterface
{
//Explicit (no public and MyInterface in front)
void MyInterface.DoSomething()
{ }
//Explicit (no public and MyInterface in front)
string MyInterface.GetSomething(int number)
{
return number.ToString();
}
}
Явные и неявные реализации определений из интерфейса могут быть смешаны. Следовательно, мы можем быть уверены, что получим доступ ко всем членам, определенным интерфейсом, если мы передадим экземпляр этому интерфейсу.
Комментарии
Отправить комментарий