Интерфейсы, как и классы, могут наследоваться:
interface IAction { void Move(); } interface IRunAction : IAction { void Run(); } class BaseAction : IRunAction { public void Move() { Console.WriteLine("Move"); } public void Run() { Console.WriteLine("Run"); } }
При применении этого интерфейса класс BaseAction должен будет реализовать как методы и свойства интерфейса IRunAction, так и методы и свойства базового интерфейса IAction, если эти методы и свойства не имеют реализации по умолчанию.
Однако в отличие от классов мы не можем применять к интерфейсам модификатор sealed, чтобы запретить наследование интерфейсов.
Также мы не можем применять к интерфейсам модификатор abstract, поскольку интерфейс фактически итак, как правило, предоставляет абстрактный функционал, который должен быть реализован в классе или структуре (за исключением методов и свойств с реализацией по умолчанию).
Однако методы интерфейсов могут использовать ключевое слово new для скрытия методов из базового интерфейса:
IAction action1 = new RunAction(); action1.Move(); // I am moving IRunAction action2 = new RunAction(); action2.Move(); // I am running interface IAction { void Move() => Console.WriteLine("I am moving"); } interface IRunAction : IAction { // скрываем реализацию из IAction new void Move() => Console.WriteLine("I am running"); } class RunAction : IRunAction { }
Здесь метод Move из IRunAction скрывает метод Move из базового интерфейса IAction. Это имеет смысл, если в базовом интерфейсе определена реализация по умолчанию, как в случае выше, которую нужно переопределить. И в случае выше, если переменная представляет тип IRunAction, то для метода Move вызывается реализация этого интерфейса:
IRunAction action2 = new RunAction(); action2.Move(); // I am running
Иначе если переменная представляет тип IAction, то для метода Move применяется реализация этого интерфейса:
IAction action1 = new RunAction(); action1.Move(); // I am moving
Но класс RunAction может переопределить метод Move сразу для обоих интерфейсов.
IAction action1 = new RunAction(); action1.Move(); // I am tired IRunAction action2 = new RunAction(); action2.Move(); // I am tired interface IAction { void Move() => Console.WriteLine("I am moving"); } interface IRunAction : IAction { new void Move() => Console.WriteLine("I am running"); } class RunAction : IRunAction { public void Move() => Console.WriteLine("I am tired"); }
При наследовании интерфейсов следует учитывать, что, как и при наследовании классов, производный интерфейс должен иметь тот же уровень доступа или более строгий, чем базовый интерфейс. Например:
public interface IAction { void Move(); } internal interface IRunAction : IAction { void Run(); }
Но не наоборот. Например, в следующем случае мы получим ошибку, и программа не скомпилируется, так как производный интерфейс имеет менее строгий уровень доступа, нежели базовый:
internal interface IAction { void Move(); } public interface IRunAction : IAction // ошибка IRunAction может быть только internal { void Run(); }