Интерфейсы в C#

У тех, кто только начинает осваивать C# часто возникает вопрос что такое интерфейс и зачем он нужен.

Сначала о том, что можно найти по первой же ссылке в поисковике. В большинстве статей смысл интерфейса разъясняется как «договор» о том, что должен содержать класс, какие свойства и методы. Например у нас есть интерфейс:

public interface IForecast
{
    int GetForecast(int value);
    int Size { get; set; }
}


Соответственно, если какой-то класс реализует данный интерфейс, то он должен содержать реализацию метода int GetForecast(int value) и свойство Size.

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

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



Дополнение
Сразу после публикации на меня обрушили море критики, сначала я пытался отвечать, но потом понял, что смысла нет. Все критики упирают на то, что я написал в предыдущем абзаце и пытаются приводить сложные примеры проектов где много классов, всякие ссылки туда-сюда, поддержка командой и прочее. Я наверно был не прав, что так коротко подвел итог вступления. Но суть в том, что интерфейс нужен далеко не всегда. Если у вас ваш личный (или просто не очень большой) проект, который не планируется масштабировать, на который ни кто не ссылается и, самое главное, который успешно работает, то введение в проект интерфейсов ничего не изменит. И не надо придумывать истории, что где-то кто-то однажды реализовал интерфейс и обрел бессмертие. Если бы интерфейс был нужен везде, он был бы неотъемлемой частью класса.

Это статья о том, как можно использовать интерфейс не для связки между проектами, а внутри одного проекта. По этому поводу критики пока еще не было.

Конец дополнения

К счастью возможности интерфейса намного интереснее. Интерфейс может задать общий признак для разнородных объектов, а это открывает огромные возможности по части гибкости кода.

Например, предположим у нас есть два класса:

class First
и
class Second


Это два совсем разных класса, но пусть у них будет что-то общее, т.е. мы хотим, чтобы один метод работал с ними обоими без дополнительной логики. В таком случае мы можем реализовать общий интерфейс, т.е. объявить эти классы как

class First : IForecast
и
class Second : IForecast


Теперь мы можем сделать общий метод для них:

void AnyMethod(IForecast anyClass)
{
      var value = anyClass.GetForecast(10);    
}


Как видно, переменная value получит значение функции GetForecast от того класса, который будет передан в качестве параметра без дополнительных действий по приведению типов и т.п.

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

...
IForecast any;
…

А потом:

if(...) any = new First();
else any = new Second();


Можно пойти еще дальше и объявить массив (или list) таких объектов:

var array = new IForecast[2];
array[0] = new First();
array[1] = new Second();


А потом можно например вычислить сумму всех свойств Size:

var summ = 0;
foreach (var forecast in array)
{
      summ += forecast.Size;
}


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

public class BaseClass
{
    public int GetValue(int value)
    {
        return value * 2;
    }
}

public class Second: BaseClass, IForecast

IForecast frc;
frc = new Second();
var frcBase = (BaseClass) frc;
var result = frcBase.GetValue(45);


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

Например добавим в наш проект еще один интерфейс:

public interface IForecast2
{
int GetForecast(int value);
}


И создадим новый класс, наследующий оба интерфейса:

public class Third: IForecast, IForecast2
{
    int IForecast.GetForecast(int value)
    {
        return value + Size;
    }

    public int Size { get; set; }

    int IForecast2.GetForecast(int value)
    {
        return 2 * value + Size;
    }
}


Это называется явной реализацией интерфейса. Теперь можно построить такую конструкцию:

 var third = new Third {Size = 10};

 var v1 = ((IForecast) third).GetForecast(100);
 var v2 = ((IForecast2)third).GetForecast(100);
 
Console.WriteLine(v1+v2);


Интересно, что при реализации таких интерфейсов методам не могут быть назначены модификаторы доступа (“public” или что-то еще), однако они вполне доступны как публичные через приведение типа.

Как видно, это работает, но выглядит слишком громоздко. Чтобы как-то улучшить код, можно написать несколько иначе:

var third = new Third {Size = 10};

 var bad = (IForecast) third;
 var good = (IForecast2) third;

 var v1 = bad.GetForecast(100);
 var v2 = good.GetForecast(100);

Console.WriteLine(v1+v2)
;

bad и good будут ссылаться на third, но иметь в виду разные интерфейсы. Привидение можно сделать один раз, а его результат потом использовать многократно. Возможно, что в некоторых случаях это сделает код более читаемым.

Еще одно применение интерфейса — быстрое изготовление заглушек для функций.
Например, вы в команде строите большой проект и ваш класс зависит от класса, который пишет коллега. Но еще не написал. Мудрый начальник подготовил интерфейсы всех основных классов еще на первом этапе разработки проекта и вы теперь можете не ждать коллегу, а реализовать класс-заглушку для своего класса. Т.е. временный класс не будет содержать логики, а будет только делать вид что работает: принимать вызовы и возвращать адекватные значения. Для этого надо только реализовать тот же интерфейс, что получил ваш коллега.

Работающий проект со всеми примерами из этой статьи можно посмотреть здесь: ссылка
Поделиться публикацией
Похожие публикации
Ой, у вас баннер убежал!

Ну. И что?
Реклама
Комментарии 76
    +6
    Подводя итог этой части, если какой-то интерфейс реализуется только в одном единственном классе, то не тратьте время на него. Он просто не нужен.

    Это, заметим, уже неправда. Если у вас потребитель и реализация находятся в разных сборках, то использование интерфейса может позволить упростить управление зависимостями, начиная с того, что потребитель не будет иметь никакой информации о реализации, и заканчивая тем, что потребитель интерфейса может собираться под .net 4, а реализация — под 4.7.


    У объявления через интерфейс есть один недостаток: вам будут доступны только методы и свойства, объявленные в интерфейсе и самом классе

    … только в интерфейсе. И это не недостаток, это смысл использования интерфейсов.


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

    Во-первых, иногда вам надо иметь разные типы возвращаемых значений (которые являются частью сигнатуры, но не позволяют делать перегрузку). Самый яркий пример — GetEnumerator.


    Во-вторых, когда интерфейсы разрабатывают разные люди (а класс должен реализовать их все), пересечение имен методов — вполне типовая ситуация.


    Интересно, что при реализации таких интерфейсов методам не могут быть назначены модификаторы доступа

    … потому что метод, реализующий метод интерфейса, всегда публичный.

      –8
      Похоже, вы прочитали по диагонали и не все поняли, что я имел в виду. Я только со вторым замечанием соглашусь, хотя это не меняет общей сути.
        0

        То есть когда вы написали "если какой-то интерфейс реализуется только в одном единственном классе, то [...] он просто не нужен" — вы имели в виду не это, а что-то другое?

          –4
          Многие задают вопрос типа «Я пишу проект, зачем мне делать в нем интерфейсы?». Я объяснил, что если кроме этого проекта ваш класс нигде больше не существует, то и интерфейс не нужен. Люди удаляют интерфейс и не видят разницы, а значит, полагают они, интерфейс — это что-то избыточное. Вся статья о том, что это не так. Интерфейсы проявляют себя либо в командных проектах, либо при несколько нестандартном взгляде на них. Как в случае с реализацией двух интерфейсов я показал, что можно получить немножко больше того, что изначально было задумано для исключения неоднозначности.
            +1
            Я объяснил, что если кроме этого проекта ваш класс нигде больше не существует, то и интерфейс не нужен.

            Так это же неправда.


            Люди удаляют интерфейс и не видят разницы, а значит, полагают они, интерфейс — это что-то избыточное.

            Если люди удалили интерфейс и не увидели разницы, значит в их ситуации интерфейс правда избыточен.


            Интерфейсы проявляют себя либо в командных проектах, либо при несколько нестандартном взгляде на них.

            Интерфейсы прекрасно себя проявляют при использовании по назначению даже в сольных проектах.

              –6
              Я понял, вы просто из принципа спорите.

              Я объяснил, что если кроме этого проекта ваш класс нигде больше не существует, то и интерфейс не нужен.
              Так это же неправда.

              Что здесь не так? Расскажите, как добавление интерфейса к работающему проекту из пары классов что-то изменит.

              Статья для тех, кто еще не столкнулся с необходимостью использовать интерфейсы и не может понять зачем они, если все и так работает.
                +1
                Расскажите, как добавление интерфейса к работающему проекту из пары классов что-то изменит.

                Это от "пары классов" зависит.


                Например: у вас есть сборка Impl, содержащая классы A и B, и есть сборка Client, содержащая класс C, зависящий от класса A. В тот момент, когда вы добавляете IA (A: IA), вы разрываете прямую зависимость, и позволяете разработчику C делать то, что он считает нужным, и так, как он считает нужным, и одновременно упрощаете разработчку A жизнь, уменьшая количество публичных обязательств его класса. Собственно, после этого A можно сделать internal, и вообще не думать, что кто-то на него завяжется.


                А есть ведь и более сложные ситуации: вот у вас есть A и B в одной сборке, и вам надо разбить эту сборку на две для упрощения поддержки. Но вот беда: A и B, которые должны оказаться в разных сборках, зависят друг от друга. Выделение интерфейсов (хотя каждый интерфейс будет реализован ровно одним классом) позволяет решить эту задачу.


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

                А из вашей статьи так и не понятно, зачем они, если и так все работает.

                  –2
                  Вы привели пример командной разработки, что я и говорил.
                    0

                    Эээ… нет. Второй пример не имеет никакого отношения к командной разработке.

                      –3
                      Но он и к сути вопроса не имеет отношения. Совсем не обязательно, что все вокруг построено на сложных проектах с многочисленными зависимостями. Вот тут ниже заминусили мое предложение добавить интерфейс к HelloWord — это потому что придется согласиться со мной?
                        0
                        Но он и к сути вопроса не имеет отношения

                        К сути какого вопроса? "Зачем нужны интерфейсы"? Имеет, и прямое.


                        Совсем не обязательно, что все вокруг построено на сложных проектах с многочисленными зависимостями.

                        … так вот интерфейсы нужны как раз тогда, когда у вас сложность проекта переваливает за некий предел (если не брать в расчет те случаи, когда вам интерфейсы навязаны требованиями). Не переваливает — не нужны.


                        Вот тут ниже заминусили мое предложение добавить интерфейс к HelloWord — это потому что придется согласиться со мной?

                        Нет, потому, что это бессмысленный пример.

                  0

                  Да банально для юнит-тестов.
                  Есть у вас предположим в проекте одна реализация сервиса А. Вы предлагаете без интерфейса внедрять её в другие классы.
                  Да, есть фреймворки которые умеют мокать даже такие внедрения, но гораздо проще замокать интерфейс, а не конкретную реализацию.

                    –1
                    Ну хоть кто-нибудь, прочитайте текст прежде чем что-то отвечать. Где я что предлагал внедрять?
                      0

                      Можно пример проектов, где не нужен DI и юнит-тесты? Я про промышленный уровень, а не про личные хеллоуворлды.

                +4
                Я объяснил, что если кроме этого проекта ваш класс нигде больше не существует, то и интерфейс не нужен.

                SOLID, «Слабая связанность», DI, IoC.
                Погуглите эти фразы, чтобы не делать столь громких и, одновременно, неуместных заявлений.
                  –6
                  При чем здесь все это? Добавьте интерфейс к HelloWord'у и покажите всем как лучше будет работать программа, и как я ошибался.
                    +3
                    Мы говорим о хелловорлдах или о программировании, как профессии? Зачем с самого начала в головы начинающих программистов вкладывать ошибочные мысли?
                    Я допускаю, что вы неправильно ФОРМУЛИРУЕТЕ эту мысль даже для самого себя. Это должно звучать примерно так:
                    Применение интерфейса имеет, как положительный эффект — снижение уровня связанности объектов, что положительно сказывается на возможности расширения функционала разрабатываемого ПО, масштабирования и внесения в него правок. Так и негативные — некоторое увеличение расхода системных ресурсов, увеличение объёма кода и времени на разработку. По этому программист должен определять необходимость применения интерфейса в зависимости от конкретной ситуации.

                    Мысль можно развить, дополнить, добавить уточнения, но, согласитесь, это уже намного лучше, чем
                    если кроме этого проекта ваш класс нигде больше не существует, то и интерфейс не нужен.
                      –3
                      Прочтите еще раз самые первые слова в статье и подумайте для вас это написано или нет. Я вполне допускаю, что вы для себя вопрос интерфейсов давно закрыли, но, так уж жизнь устроена, в программирование постоянно приходят новые люди и они не обязательно заняты на сложных коммерческих проектах. И когда они встречаю интерфейсы в разных примерах, то закономерно хотят понять для чего это, если у них все и так работает. Тот факт, что интерфейсы нужны вовсе не в каждом проекте, как мне кажется, не требует доказательств.
                        +1

                        Тогда бы стоило написать, зачем они действительно нужны. То есть SOLID, DI, IOC, полиморфизм и вот это все.


                        А у вас "можно методы с одинаковыми именами сделать, если никак не придумать уникальное". Статья наполовину про то, что "по назначению использовать интерфейсы вам пока не надо, поэтому можно вот такую штуку сделать, потому что можем".

                          0
                          Прочитайте ещё раз начало моего ответа. Заявлять ненужность интерфейсов даже для однократной реализации — нельзя. ОСОБЕННО в образовательных целях. Какой-нибудь студент это прочитает, примет за чистую монету… за истину в последней инстанции и поимеет большие проблемы в процессе развития карьеры. А перечисли плюсы и минусы интерфейсов, а так-же те фразы, которые я вам предлагал погуглить с самого начала — то и вы минусов бы не нахватали и студенту жизнь бы чуть-чуть облегчили.
                            0

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

                      +1
                      Контрпример. В моем движке есть
                      interface IFont
                      {
                          void Draw(...);
                      }
                      


                      Этот интерфейс реализован одним лишь классом
                      class SpriteFont : IFont
                      {
                          public void Draw(...);
                          ...
                      }
                      


                      По вашим словам, он тут не нужен. Однако, все другие классы, которые как-то завязаны на шрифтах (например Label) используют не SpriteFont, а IFont. Догадаетесь, почему?

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

                      Вы рассказали о том, что интерфейсы создают гибкий код, но не сказали, почему. Потому что интерфейсы — это описание протокола взаимодействия между классами. И заявлять, что
                      если кроме этого проекта ваш класс нигде больше не существует, то и интерфейс не нужен
                      очень сомнительно.
                        –2
                        Ну если сомнительно, то напишите как интерфейс к классу, который есть только в одном экземпляре и на который больше ни где ни кто не ссылается, вам чем-то поможет. Напишите.

                        А, все рано же не напишите…
                          0

                          Во-первых, класс всегда "только в одном экземпляре". Во-вторых, а зачем вообще нужен класс, на который никто нигде не ссылается?


                          (хотя, заметим, я знаю один пример, зачем, но не думаю, что вы его имеете в виду)

                            0
                            ээээ, dependency injection?
                              0

                              Для injection класс нужно использовать как минимум при создании контейнера.

                                0

                                Чтобы при dependency injection класс-реализация нигде не упоминался, нужно (а) автосканирование и (б) либо базовый класс, либо, собственно, интерфейс — который комментарием выше и предлагают не писать.

                    0
                    Что GetEnumerator яркий пример, я бы не говорил так, учитывая, что тут разработчики применили грязный хак с утинной типизацией.
                      0

                      Это на стороне потребителя там утиная типизация (да и то не всегда). А вот на стороне реализации IEnumerable<T> честные explicit, потому что иначе не получится.

                    0
                    У меня были неоднократные попытки использования интерфейсов, когда я не понимал их истинное предназначение, да и больших проектов в составе нескольких разработчиков я не писал. И пришел к тем же выводам, что и автор поста.
                    Но сейчас я совершенно не согласен, потому что начал использовать интерфейсы правильно, мои библиотеки начали использовать другие разработчики, которые наверняка попытаются вернуть int там, где ожидается string, например. Так что, советую пост удалить и попытаться еще раз построить код правильно.
                      –4
                      Еще один «не читал, но осуждаю». Прочтите еще раз, а потом удалите свой комментарий, т.к. он не к месту. Устал повторять, но что вы все зациклились на командной работе? Я в последнем абзаце как раз упомянул случай как интерфейсы помогают в таком случае, но статья вообще не о том.
                        0
                        Ваше дополнение всеравно не верно. Интерфейсы не нужно внедрять в небольшое приложение для себя, не потому что они там не нужны, а потому что их нужно продумать до написания приложения. Интерфейсы способны дать вам понимание как взаимодействуют части приложения и как оно работает в целом еще до написания какой либо имплементации.
                          –1
                          Т.е. вы не допускаете, что интерфейс может быть не нужен? Вот если погуглить по «c# Is there always an interface», то окажется, что там, на западе, где и придумали C# вовсе не считают, что интерфейсы надо везде «сувать». А только там и тогда, когда это нужно. Что логично, в общем-то. Я ни разу не сказал, что интерфейсы лишние в любом проекте, но все словно оглохли. Может у вас секта какая-то свидетелей интерфейса? :)
                            0
                            Я не писал что интерфейс нужен для каждого класса. Я написал что внедрять их надо до написания непосредственно всех необходимых имплементаций.

                            Ясен красен, что интерфейс не нужен для DTO\VO\Entity классов.
                            Интерфейсы нужны на границах слоев. В тех местах где ваше приложение взаимодействует с БД, файловой системой, сторонними сервисами. В тех местах, где возможны множественные имплементации.
                            Они позволяют вам увидеть как ваше приложение будет работать до того, как вы заимплементите все эти вещи.
                              –1
                              Где тут противоречие с моей статьей? Я пишу, что если все работает без интерфейсов (понимаете, уже работает, все, задача исполнена), то добавив интерфейс вы ни чего не измените и не улучшите. Фантазии на тему «а вдруг потом понадобится» ничего не меняют. Это частный случай, которого может и не быть.
                                0
                                Вот это все работает без интерфейсов
                                public class A {
                                    public void Run() => Console.WriteLine("A");
                                }
                                
                                public class B {
                                    public void Run() => Console.WriteLine("B");
                                }
                                
                                public class C {
                                    public void Run() => Console.WriteLine("C");
                                }
                                
                                object GetSmth() => new B();
                                
                                void Main()
                                {
                                    var smth = GetSmth();
                                
                                    if (smth is A a)
                                        a.Run();
                                
                                    if (smth is B b)
                                        b.Run();
                                
                                    if (smth is C c)
                                        c.Run();
                                }

                                Тут ничего не изменится и не улучшится с добавлением интерфейса?

                                  –2
                                  По моему нет. Но вам сейчас расскажут про поддержку кода, работу в команде, библиотеки и прочие интересные, но совершенно не уместные штуки.

                                  Хотя интерфейс здесь конечно просто просится.
                                    0

                                    Мне этого рассказывать не надо, я про все это знаю. Я бы на ревью этот код завернул. И в собственных проектах тоже без весомой причины такое никогда бы не написал.


                                    Вы уж определитесь, "интерфейс просится" или "не изменится и лучше не станет"?

                                      –1
                                      Что тут не понятно? Три класса имеют одинаковые методы. Было бы красиво прикрутить интерфейс, который они реализую. Но в данном случае ничего кроме красивости это не даст. Все как работало, так и будет работать. Я не знаю какой там контекст, но если это законченный проект (путь такой странный), то интерфейсы ему ни чем не помогут.

                                      что касается ревью, то пожалуй:

                                       interface Ix {
                                              void Run();
                                          }
                                      
                                      public class A: Ix
                                          {
                                              public void Run() => Console.WriteLine("A");
                                          }
                                      
                                          public class B: Ix
                                          {
                                              public void Run() => Console.WriteLine("B");
                                          }
                                      
                                          public class C: Ix
                                          {
                                              public void Run() => Console.WriteLine("C");
                                          }
                                      
                                          class Prg
                                          { 
                                              object GetSmth() => new B();
                                      
                                              public  Prg()
                                              {
                                                  var smth = (Ix)GetSmth();
                                                  smth.Run();
                                                  Console.ReadKey();
                                              }
                                          }
                                      


                                      Это по сути то, что я написал сразу после дополнения, если вы читали (многие по-моему не читали дальше ката)
                                        +1
                                        Что тут не понятно? Три класса имеют одинаковые методы. Было бы красиво прикрутить интерфейс, который они реализую.

                                        Да, пожалуй, мне стоило назвать классы чуть иначе. Например, FooTaskRunner, BarTaskRunner и BazTaskRunner. Было бы чуть очевиднее.
                                        Понимаете, было бы не "красиво" прикрутить интерфейс. Это необходимо, потому что ООП и далее по тексту.


                                        Ваша логика примерно такая: можно не делать интерфейсы, если можно написать без них. Это примерно тот же уровень логики, как "можно не писать грамотно, мы не в школе". Что угодно можно написать без интерфейсов. Но это не значит, что это нужно делать.

                                          –1
                                          Ок, у вас в проектах все без исключения классы имеют интерфейсы потому что ООП? И еще наверно абстрактный класс до кучи? Понимает, здесь в обсуждении все приводят примеры когда без интерфейсов никак или очень сложно. Но утверждать, что это всегда так не правильно.

                                          Я вот просто открыл гитхаб и набрал в поиске «C#», перешел по первой же ссылке — какая-то игра «JumpAttacker». Довольно объемный проект. Походил по файлам. Нет интерфейсов… Может плохо искал. Пошел по другой ссылке (что-то китайское «GavinYellow»). В некоторых классах были интерфейсы, в некоторых нет. Идем далее «statianzo» — где-есть, где-то нет интерфейса.

                                          Я уже ниже писал, что если погуглить англоязычные форумы, то там пишут, что интерфейсы не надо липить везде подряд вот или вот
                                          И вы уж извините, но я склонен больше доверять тем, кто придумал C#.
                                          Do define an interface if you need to provide a polymorphic hiercharcy of value types
                                          , а если полиморфизм не нужен, то не захламяйте код.
                                            +1
                                            Ок, у вас в проектах все без исключения классы имеют интерфейсы потому что ООП? И еще наверно абстрактный класс до кучи?

                                            Нет. Интерфейсы у меня там, где они необходимы, а не везде. Например, там, где есть отношение "является", или где необходимо предоставлять классу какие-то зависимости.
                                            И абстрактные классы, не поверите, тоже там, где они нужны. Но вообще редко приходится их использовать.
                                            Никто это и не утверждает. Все говорят вам, что ваши утверждения про то, что если реализация одна или что без интерфейса тоже заработает, то он не нужен — бред.


                                            Я уже ниже писал, что если погуглить англоязычные форумы, то там пишут, что интерфейсы не надо липить везде подряд вот или вот

                                            Вам здесь еще никто и не сказал, что их надо лепить везде подряд.

                                              0
                                              что если реализация одна или что без интерфейса тоже заработает, то он не нужен — бред.
                                              Почему?

                                              Вам здесь еще никто и не сказал, что их надо лепить везде подряд.


                                              Да все только про это и говорят. Я пишу, что интерфейс нужен вовсе не везде а только там, где он нужен, а мне отвечают, что я не прав. Вы же программист? Утверждение обратное «Интерфейс нужен не везде» — это «Интерфейс нужен везде». И при этом все отмечают, что у них как бы не все классы под интерфейсами, но я все равно не прав.
                                                0
                                                Я пишу, что интерфейс нужен вовсе не везде а только там, где он нужен

                                                … как определить, где нужен интерфейс?

                                                  0
                                                  Ну это каждый сам решает исходя из задачи. Если бы было четкое правило, то его бы компилятор проверял и вы бы просто проект не собрали.
                                                    0

                                                    Ну то есть на вопрос "я пишу проект, зачем мне делать в нем интерфейсы?" у вас ответа нет?

                                                      –2
                                                      У вас его тоже нет в виде универсального рецепта. Приступая к проекту, вы определяете круг задач и исходя из этого решаете где нужен интерфейс.

                                                      Если вас просят вскопать огород, вы приходите с лопатой, если забить гвоздь, то с молотком. Вы же не потащите «на объект» все возможные инструменты. Так и здесь.

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

                                                        Да. Именно поэтому я не пишу статей про интерфейсы в C#.


                                                        Вы уже поняли, что зря тут на меня наехали

                                                        Отнюдь. Вы пока не переубедили меня ни в одном пунктов.

                                              0
                                              Do define an interface if you need to provide a polymorphic hiercharcy of value types

                                              Плохая, плохая цитата. Если ей верить, то интерфейсы надо использовать тогда, когда у вас value types (ни одного примера в вашем посте), а все остальное время надо использовать классы:


                                              Do favor defining classes over interfaces.
                                              Do use abstract [...] classes instead of interfaces to decouple the contract from implementations.

                                              … и только если нужно множественное наследование, тогда:


                                              Consider defining interfaces to achieve an effect similar to that of multiple inheritance.

                                              К счастью, это не "те, кто придумал C#". И сейчас разрабатывают не так: в современных публичных API намного пропорция "интерфейсы — абстрактные классы" — по крайней мере, по моим наблюдениям — существенно сильнее сместилась в сторону интерфейсов.

                                    0
                                    Если задача уже исполнена, то зачем об этом писать статью?
                                      0
                                      Вы меня тролите что-ли?
                                      0
                                      Я пишу, что если все работает без интерфейсов (понимаете, уже работает, все, задача исполнена), то добавив интерфейс вы ни чего не измените и не улучшите.

                                      Это зависит от того, что считать улучшением.

                                        –2
                                        Я даже не представляю, что можно было бы ответить на это. Это зависит от того, что считать правильным ответом. Так наверно. Теперь вы голову ломайте.
                                          0

                                          Да нет, это вполне нормальный жизненный вопрос. Когда вы делаете рефакторинг, вы (обычно) улучшаете код. Поэтому даже если что-то работает без интерфейсов, но можно отрефакторить, применив интерфейсы, станет лучше (читаемее, например).


                                          Реальный вопрос возникает дальше: а нужно ли это улучшение? Потому что если этот проект отдали и забыли, и поддерживать его не надо — то, возможно, возиться с рефакторингом тоже не надо, потому что не окупится. А вот если оно работает, но завтра могут прийти и попросить поправить...


                                          Собственно, это все рассуждения, который собственно к интерфейсам отношения не имеют, это общие мысли про рефакторинг. В моем опыте случаев, когда что-то сначала писали "просто чтобы работало", а потом рефакторили на "более правильно", очень и очень много.


                                          Я сегодня добавлял интерфейс там, где его не было несколько лет (и все прекрасно работало без него).

                                0

                                Я храбро разрабатываю в одиночку. У меня есть коллекция, по которой я хочу иметь возможность итерировать, однако это, будучи коллекцией, не знаю, каких-то узлов в дереве, а именно — трехмерных объектов на сцене, наследует определенные свойства абстрактного класса, реализующего отрисовку геометрии. Абстрактный класс и его наследники предназначены для вывода, перебор для физического движка. В итоге мне нужно реализовать два интерфейса. Как это сделать? В C# нет множественного наследования.


                                Или у меня есть интерфейс Event. На какой черт мне нужен абстрактный класс, в котором не реализован ни один метод? Я просто сделаю интерфейс IEvent (вдобавок некоторые события опять же могут реализовывать несколько интерфейсов).


                                Все в рамках одного проекта и без команды. Нужны интерфейсы? Ну можно было нагородить дерево наследования как-то хитро, избегая таких случаев, создавая непонятные проблемы. А можно просто реализовать интерфейс.

                                  –2
                                  Извините, и что? Я где-то был против этого? И это, поосторожнее, за «На какой черт мне нужен абстрактный класс» здесь могут жестко заминусить те, кто у кого в любимом проекте есть абстрактные классы. Ни кто ж не будет вникать в ваш конкретный случай, как я понял.
                                    0
                                    В вашей задаче не нужны ни интерфейсы, ни множественное наследование, ни сложная иерархия наследования, она только создаст дополнительные проблемы.

                                    en.wikipedia.org/wiki/Entity%E2%80%93component%E2%80%93system
                                    0
                                    Ну само рассуждение на тему «это для командной работы, а это для одиночной» — имхо, некорректны. Т.е. если программист, в начале карьеры работает сам по себе, то ему не нужно смотреть как идет разработка в корпоративных проектах? А еще сразу отбрасываем open source проекты? Или когда программист «дорастёт», то ему учиться программировать по новому?

                                    Ну даже если он разрабатывает например сам, возьмем разработку сайтов. Вот он написал, первое что пришло в голову — логгер, который пишет лог в файл

                                    class MyFileLogger
                                    { 
                                        public void LogMessage(string message) {}
                                    }
                                    


                                    И всё у него было хорошо, пока ему не потребовалось писать лог в базу. Ему придется переписать или реализацию метода, или все ссылки на MyFileLogger исправить на MyDBLogger. А если он юзает свои наработки, возможно, что логгер в какой-то подключаемой библиотеке. Одни недостатки. То ли дело, если бы наш программист заранее подумал, «а мало ли», и сделал интерфейс:

                                    interface IMyLogger 
                                    {
                                        void LogMessage(string message);
                                    }
                                    

                                    и использовал ссылки этого типа, чтобы отвязаться от реализации.

                                    Мой пример утрирован, но думаю, он должен дать пищу для размышлений.

                                    Так же есть такое мнение, с которым лично я полностью согласен: «программировать нужно на уровне интерфейсов, а не на уровне реализации». Интерфейсы дают более чистое представление о структуре и логике проекта.
                                      –2
                                      ЛЮДИ!!! Прочитайте текст. Покажите мне где я написал, что интерфейсы не нужны? Вы все ослепли что-ли? Да я сам могу тысячу примеров привести, где они нужны. Я сам использую их в работе. Но утверждать, что ко всякому классу во всех проектах надо цеплять интерфейс (а вдруг пригодится) — это просто странно.
                                        0
                                        Покажите мне где я написал, что интерфейсы не нужны?

                                        Показываю:


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

                                        Вам выше рассказали почему это утверждение не соответствует действительности.

                                          –1
                                          Разве я здесь написал, что интерфейсы не нужны вообще?

                                          Я уверен, что в вашем проекте, которым сейчас вы занимаетесь (если вы реально программист) найдется не мало классов к которым нет интерфейсов.

                                          Я выше спросил надо написать интерфейс к HelloWord, но мне не ответили по существу. Да и не ответят. Общий тренд уже задан. Комментариев в поддержку не будет, чтобы минусов не нахватать от вас.
                                            0
                                            Разве я здесь написал, что интерфейсы не нужны вообще?

                                            Конечно нет. Вы написали что "интерфейсы не нужны к классам с единственной реализацией".


                                            А я вот не согласен с этим утверждением.
                                            Есть случаи когда к классу с единственной реализацией нужен интерфейс. Тестируемый код должен быть слабосвязанным.
                                            Добиться этого проще через интерфейсы, поэтому даже если у Вас есть всего одна (и больше не планируется) реализация сервиса работы с очередью для получения данных, проще выделить интерфейс IQueueDataService чтобы замокать её в юнит-тестах с полпинка. Попутно получаем все прочие плюсы слабой связанности.


                                            Расскажите где я неправ, очень будет любопытно.

                                              0
                                              Да все вы правильно пишите. Я согласен полностью. Я ошибся когда написал «единственная реализация», имея в виду, что еще и ссылок на это класс всего одна или несколько, но все они тут рядышком и ни какой «многоэтажности» даже близко нет в планах. Надо было писать подробнее.
                                              0

                                              Я вам по существу отвечу про hello world здесь, ладно? А то вы много раз про это напоминали. Обрадую: к hello world интерфейс не нужен. Но это несостоятельный пример ровно по той причине, что hello world вы пишете примерно один раз в жизни.


                                              Да, на каждый класс вешать интерфейс не нужно, это факт. Интерфейсы нужны там, где они могут обеспечить полифморфизм, сокрытие и возможность замены реализации и все такое. Но у вас про это нет ни слова, вы не объясняете, когда они нужны. Из вашей статьи и комментариев следует только то, что "если вы пилите свой небольшой проект, то зачем эти интерфейсы, если можно как-нибудь и без них накодить, чтоб работало". И это совершенно бесполезно и даже вредно. Независимо от масштаба проекта и количества разработчиков код должен быть хорошим и поддерживаемым, в том числе за счет использования интерфейсов там, где это нужно. Но где это нужно, вы так и не сказали.


                                              В первых же абзацах вы приводите какой-то случайный интерфейс и пишете "Практическая ценность такого договора минимальная". Неужели? Вы сразу бросаете серьезнейшее утверждение, при этом не приводя никакого контекста. Как используется этот интерфейс? Кто его реализует?


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


                                              У вас вроде обучающая статья. Вы ориентируетесь на тех, кто только учится, у кого нет знания терминологии. И у вас в статье с терминологией просто ужас. Интерфейсы не наследуются, а реализуются. Объявляют не "экземпляр класса", а "переменную типа". Классы с общими признаками, и возможность их использовать, не зная конкретного типа, называется полиморфизмом. Такие ошибки просто недопустимо делать, если вы хотите чему-то кого-то научить.

                                                –1
                                                А почему вы решили, что не планирую ссылаться на HelloWord? А вдруг потребуется поддержка? Все примеры здесь «притянуты за уши» ни чем не лучше друг-друга.

                                                Ни кто не хочет смириться с мыслью, что бывают простые проекты.

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

                                                По поводу терминологии. Один раз случайно «унаследовал» интерфейс и все. Если верить МСДНу, то создают экземпляр класса, а не «переменную типа». Да, не объявляют. 1:1

                                                Прочее читаю придиками не по существу.
                                                  +2
                                                  Ни кто не хочет смириться с мыслью, что бывают простые проекты.

                                                  Знаете, у меня за последние лет пять-восемь не было ни одного проекта, исключая чисто учебные или тестовые запускалки, где не всплывали бы интерфейсы.

                                                    0
                                                    Все 100% классов в ваших проектах имели интерфейсы? Учебные и тестовые проекты не являются программами по определению и обсуждению не подлежат? Это серьезно?

                                                    По ссылке из вашей единственной статьи (да, я любопытный) перешел на гитхаб в «unitycontainer», походил по классам. Интерфейсы есть далеко не везде. Может уже пора признать, что если интерфейс не нужен, то он и не нужен?
                                                      0
                                                      Может уже пора признать, что если интерфейс не нужен, то он и не нужен?

                                                      А я, вроде бы, пять часов назад написал вам: "интерфейсы нужны как раз тогда, когда у вас сложность проекта переваливает за некий предел [...] не переваливает — не нужны"


                                                      Учебные и тестовые программы за этот предел не переваливают. Простая, казалось бы, консольная программка для заливки/выгрузки схем с удаленного сайта — переваливает.


                                                      По ссылке из вашей единственной статьи (да, я любопытный) перешел на гитхаб в «unitycontainer», походил по классам. Интерфейсы есть далеко не везде.

                                                      … при этом весь смысл Automapper.Unity (а совсем не UnityContainer, за который я никак не отвечаю) ровно в том, чтобы сделать удобным взаимодействие с интерфейсом (вместо статического класса). И, что характерно, у этого интерфейса всего одна представляющая интерес реализация. Так что вы выбрали неудачный пример (ну или удачный, смотря какую точку зрения доказывать).

                                                        0
                                                        Все 100% классов в ваших проектах имели интерфейсы?

                                                        Если взять MVC, например, то, скажем, модели (те классы, которые просто представляют сущности) — могут не использовать интерфейсы. Хотя я в моделях реализовывал интерфейсы, типа IDeletable, ISorted и подобные.
                                                        Вы лично можете не использовать интерфейсы в контроллерах, хотя опять же, зависит от ситуации, да и тот же ApiController реализует IDisposable.
                                                        Так же в C# существуют статические классы (хелперы, либо классы с расширяющими методами).
                                                        А еще вложенные типы, которые тоже, на моей практике, часто не реализуют интерфейсы.
                                                        А еще, у меня сейчас открыт проект, в котором классы Program и Startup не реализуют интерфейсы.
                                                        Это просто примеры навскидку. Уверен, найдется еще множество причин не использовать интерфейсы

                                                        И, кстати, Вам не сказал lair, что «все классы должны реализовывать интерфейсы».
                                                      +1
                                                      Если верить МСДНу, то создают экземпляр класса, а не «переменную типа». Да, не объявляют. 1:1

                                                      О, вы счет ведете? Круто. Так вот:
                                                      Экземпляр класса создают. Переменную типа объявляют. Это разные вещи.
                                                      А у вас в статье "объявляют экземпляр класса":


                                                      В такой случае можно объявить экземпляр класса, реализующего интерфейс:

                                                      IForecast any;
                                                        –2
                                                        Э…
                                                        Открываем microsoft. Членами класса являются 1,2,3,… Переменных нет, но есть поля класса, которые содержат переменные класса. Идем дальше на страницу полей
                                                        Поля объявляются в блоке класса путем указания уровня доступа поля, за которым следует тип поля, а затем имя поля.

                                                        Т.е. в данном случае все таки объявление, но конечно не класса, но и не переменной, а поля. Под которым в дальнейшем подразумевается класс.

                                                        Я не понимаю, зачем это все здесь обсуждать. Очевидно у вас тоже не уверенные знания.
                                                          +1

                                                          Переменные есть в другой статье, про локальные переменные.


                                                          У вас IForecast any; — это что? Локальная переменная или поле? Приведите полный кусок кода, без пропусков.
                                                          Из текста следует, что это локальная переменная. Если вы подразумевали, что это поле, то ладно, суди это не меняет: объявляется поле класса, создается экземпляр класса.


                                                          И не увлекайтесь сильно русским мсдн-ом, там часто машинный перевод, и он откровенно кривой.


                                                          но и не переменной, а поля. Под которым в дальнейшем подразумевается класс.

                                                          Простите, что? Под полем подразумевается класс?


                                                          Я не понимаю, зачем это все здесь обсуждать. Очевидно у вас тоже не уверенные знания.
                                                          Затем, что ваша обучающая статья сдержит ошибки и обучаться кому-то по ней противопоказано.
                                                            +1
                                                            Т.е. в данном случае все таки объявление, но конечно не класса, но и не переменной, а поля. Под которым в дальнейшем подразумевается класс.

                                                            Под полем не может подразумеваться класс. Поле — это поле, у него есть тип (который может быть классом, структурой или интерфейсом).

                                                      0
                                                      Разве я здесь написал, что интерфейсы не нужны вообще?

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

                                                0
                                                Устал повторять, но что вы все зациклились на командной работе?

                                                Потому что ориентироваться надо именно на нее. И, что занятно, практики, позволяющие одному человеку (без феноменальной памяти) работать с большим и сложным проектом, — те же самые, как если бы там работала команда.

                                              +2
                                              Эээээ, а по вашему честно, что 95% вашего текста, есть в любой книге по шарпу? И остальные 5% вывод, работает, ну и нефиг трогать.

                                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                              Самое читаемое