Новые возможности интерфейсов в C# 8

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.


Для начала посмотрим на определение интерфейса у Эндрю Троелсена и Филиппа Джепикса: «Интерфейс представляет собой всего лишь именованный набор абстрактных членов. Абстрактные методы являются чистым протоколом, поскольку они не предоставляют свои стандартные реализации. Специфичные члены, определяемые интерфейсом, зависят от того, какое точно поведение он моделирует. Другими словами, интерфейс выражает поведение, которое заданный класс или структура может избрать для поддержки». И дальше по тексту: «Запомните, что при определении членов интерфейса область реализации для них не определяется. Интерфейсы — это чистый протокол и потому реализация для них никогда не предоставляется» (определение из книги ).

Отлично, вроде бы все понятно, приблизительно такая же трактовка интерфейса будет описана и в других книгах по языку, но в C# 8 интерфейс несколько пересмотрен и добавлены на первый взгляд противоречащие возможности типа. Рассмотрим же интерфейсы в C# 8 более подробно.

Default implementations или реализация членов по умолчанию


По определению, если мы наследуемся от интерфейса, то должны реализовать поведение каждого члена интерфейса. В C# 8 появилась возможность реализации члена интерфейса по умолчанию:

interface ICommand
    {
        void exec();
     
        // default implementations
        public void sendNotification(string mes)
        {
            Console.WriteLine(mes);
        }
    }

Метод «exec» является обычным абстрактным методом в интерфейсе к которым мы все очень привыкли, а вот метод «sendNotification» для интерфейса выглядит странно и предлагает свою реализацию по умолчанию.

Посмотрим как это работает:

public class AppFirstCommand : ICommand
    {
        public void exec()
        {
            // some action
            Console.WriteLine("Action complete!");
        }
    }

При реализации интерфейса мы обязаны реализовать абстрактный метод «exec» и можем опустить реализацию метода «sendNotification». Удобно?

class Program
    {
        static void Main(string[] args)
        {
            ICommand appFirstCommand = new AppFirstCommand();

            appFirstCommand.exec();
            appFirstCommand.sendNotification("Default implementations");
        }
    }

Результат выполнения:

Action complete!
Default implementations


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

ICommand appFirstCommand = new AppFirstCommand();

Иначе мы не сможем обратиться к методу «sendNotification» интерфейса, так как в классе «AppFirstCommand» нет реализации этого метода. Так работать не будет:

AppFirstCommand appFirstCommand = new AppFirstCommand();

И да, переопределить поведение метода «sendNotification» мы так же можем:

public class AppSecondCommand : ICommand
    {
        public void exec()
        {
            // some action
            Console.WriteLine("Action complete!");
        }

        // override sendNotification
        public void sendNotification()
        {
            Console.WriteLine("New implementation");
        }
    }

class Program
    {
        static void Main(string[] args)
        {
            AppSecondCommand appSecondCommand = new AppSecondCommand();

	    appSecondCommand.exec();
            appSecondCommand.sendNotification();
        }
    }

Результат выполнения:

Action complete!

override method from AppSecondCommand


В этом случае мы обращаемся напрямую к экземпляру класса «AppSecondCommand», так как в этом классе мы явно реализовали метод «sendNotification».

Чем подход с «Default implementations» удобен?


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

Отмечу, что доступны все модификаторы доступа C# для членов интерфейса реализованных по умолчанию.

Интерфейсы могут содержать статические члены


interface IStaticMembers
    {
        private static string commandName = "Default command name";

        private void build(string name)
        {
            commandName = name;
        }

        public void setCommandName(string name)
        {
            build(name);
        }
    }

Интерфейсы могут содержать виртуальные члены


Но класс, который наследует интерфейс переопределить виртуальный член не может.
Переопределять виртуальные члены интерфейсов могут только интерфейсы.

interface IVirtualMembers
    {
        public virtual void sendNotification()
        {
            Console.WriteLine("IVirtualMembers's  sendNotification");
        }
    }

    interface IOverrideVirtualMembers : IVirtualMembers
    {
        void IVirtualMembers.sendNotification()
        {
            Console.WriteLine("IOverrideVirtualMembers's  sendNotification");
        }
    }

Стоит также отметить, что так же можно определять абстрактные члены интерфейсов, но в этом нет никакого смысла.

Итак, краткий список новых возможностей интерфейсов в C# 8:

  • Default implementations или реализация членов по умолчанию;
  • Интерфейсы могут содержать статические члены;
  • Интерфейсы могут содержать виртуальные члены.

Весь код из статьи выложен на github.
Источник: https://habr.com/ru/post/499184/


Интересные статьи

Интересные статьи

Вести океанское исследовательское судно или марсианский исследовательский шаттл – дело серьёзное. Остаётся надеяться, что приборная панель будет высшего качества. Ширина в два шип...
Привет, Хабр! Многие уже начинают готовиться к новогодним праздникам, закупать подарки, кто-то планирует путешествия на длинные новогодние выходные. А у нас в JetBrains пока еще горячая пора в...
В предыдущей статье, когда мы рассказывали про нашу новую услугу VPS с видеокартой, мы не затронули некоторые интересные аспекты использования виртуальных серверов с видеоадаптерами. Пришло время...
Среди советов по улучшению юзабилити интернет-магазина, которые можно встретить в инете, один из явных лидеров — совет «сообщайте посетителю стоимость доставки как можно раньше».
Автокэширование в 1с-Битрикс — хорошо развитая и довольно сложная система, позволяющая в разы уменьшить число обращений к базе данных и ускорить выполнение страниц.