Как стать автором
Обновить

Комментарии 52

В C# 8 появилась возможность реализации члена интерфейса по умолчанию:

Наконец-то, давно пора!


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

Ну вот и пришли к тому, что давно было в абстрактных классах C++. И стоило велосипед под названием "интерфейсы" изобретать?!

Интерфейсы по прежнему не могут содержать состояние (поля), чего не скажешь об абстрактных классах, которые в C#, кстати, также есть.
Зато интерфейсы смогут иметь статические поля и статические методы.
И? По факту можно сделать и без интерфейса, завести internal class к примеру и в нём хранить. Так что это обходилось бы без каких либо проблем.
«По факту» можно в принципе обойтись без интерфейсов. Вопрос только в том насколько это удобно.
Ну уж отказываться от интерфейсов я не предлагал. Без IoC не жизнь.
Возможно такое поведение стерло бы границу между интерфейсом и абстрактным классом)

Они ещё немного подумают и добавят и поля ;) и назовут это новой "революционной" возможностью C# 9 или 10.

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

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

Сигнатура метода другая. Здесь нет переопределения.
За наводку спасибо, но уж лучше разбираться по docs.microsoft.com и оригинальному репозиторию от Microsoft.
Там ещё и результат выполнения отличается от того, что должен быть по коду:
Результат выполнения:

Action complete!

override method from AppSecondCommand
Спасибо за замечание, поправил недоразумение)

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

Возможно, а возможно и нет. Расширять интерфейс не поддерживая классы его реализующие заманчивая возможность)
Имел опыт написания на Swift — мне понравилась их идея с протоколами и extension'ами, когда можно расширить любой класс не только методами

В том-то и дело, что нельзя. Нет доступа к внктреннему состоянию объекта — переменных нет.

Это очень удобно например для IEnumerable (что они правда пока что не сделали)
Потому что в 99.99% случаях при имплементации IEnumerable приходится писать два GetEnumerator, сейчас же можно сделать реализовать не обобщенный интерфейс в обобщенном.
И ещё очень надеюсь что наконец то ICollection станет реализовывать IReadonlyCollection. (Это брейкинг ченж без дефолтных имплементаций). Лишь бы они на это не забили.
Когда добавят возможность писать
private:
protected:
public:
что бы не писать перед каждым методом
Хм. Допустим имеет место модификатор:
protected
для интерфейса:
protected interface ICommand
Ну как то так это должно выглядеть. И все нормально если каждый член имеет реализацию по умолчанию (каждый член будет иметь модификатор доступа интерфейса):
void exec();
{
    return 1;
}
     
void sendNotification(string mes)
{
     Console.WriteLine(mes);
}


Вот только в случае с абстрактными членами возникает сумятится:
protected interface ICommand 
{
	void exec();
	{
		return 1;
	}
     
	void sendNotification(string mes)
	{
		 Console.WriteLine(mes);
	}
	
	void newMethod();
}

Каким должен быть модификатор доступа у «newMethod»?..
Как по мне это все вносит лишнюю сложность)
Сдаётся мне, товарищ хотел эту штуку иметь везде, а не только в описании интерфейсов. Чтобы при описании класса можно было один раз объявить область public: в которой все методы, свойства и поля были бы публичными. Без необходимости указывать доступность каждого элемента по отдельности.
Мм… Возможно в классах такое поведение было бы удобным… Но опять же, для класса не всегда хотелось бы иметь все члены с одним модификатором. Допусим в классе с «областью» public мы хотим иметь некий вспомогательный приватный метод и тут выход таков, что бы указывать private явно перед таким методом, что так же вносит некий сумбур в код.
Ну тогда приватный метод переезжает в область приватных методов.
Если бы меня спросили, как я это вижу — я бы ответил «с использованием директив препроцессора».
Пишем что-то типа
#Public
string Property1 {get; set;}
void Method1() {}
#EndPublic

#Private
int field1;
void Method2{}
#EndPrivate

public event Action PublicEvent();
Чем такая запись плоха?
class A : I {
  public:
    string Property1 {get; set;}
    void Method1() {}

  private:
    int field1,field2,field3;
    void Method2() {}

  public override(I): // и даже так
    void I_method1() {}
...
Вполне удобно) Мне нравится
Тем, что теоретически с директивами можно реализовать плагином к студии, а ваш вариант — добавление этой фичи в синтаксис языка.

Почти наверняка никогда. И хорошо: группировка методов по признаку публичности/приватности вместо группировки по смыслу (по степени логической связанности методов) — порочная практика.

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

Ну что тут сказать? Программист на Паскале может на любом языке написать программу на Паскале...

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


Такое ощущение что разрабы в MS (и не только) привыкли пилить всё на интерфейсах и начисто забыли о существовании абстрактных классов.
Как заметили выше — осталось дать возможность объявлять в интерфейсе поля.
Дело в том, что в C# не поддерживается множественное наследование классов. Возможно в этом причина широкого использования интерфейсов во всевозможных паттернах.

Причём, чем оно им помешало, мне до сих пор непонятно...

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

А это тут каким боком? Не понял.
Допустим у вас есть некий интерфейс, который реализован несколькими класами. В какой то момент вы решили немного расширить интерфейс новым членом(скажем методом). До C# 8 пришлось бы в этих классах либо реализовывать этот новый член, либо ставить заглушку, но в любом случае изменения коснулись бы всех классов реализующих этот интерфейс. Теперь же достаточно добавить для этого нового члена реалицацию по умолчанию(«Default implementations»), не изменяя и не засоряя классы наследующие интерфейс.

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

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

ИМХО, в такой ситуации код люто напрашивается на рефакторинг(interface segregation, single responsibility)
Да, толстые интерфейсы не есть хорошо, но невсегда расширение интерфейса приводит к размытию его ответсвенности. И в таком случае это все таки может быть полезным…
Из за отсутствия такой возможности ранее и, как раз таки, избегания добавления новых членов в интерфейсы, в дотнете ICollection и IReadonlyCollection не совместимы (потому что IReadonlyCollection появился позже).
И тогда получается, что смысл интерфейса как понятия изменяется, так как если класс реализует интерфейс, то может оказаться, что какие-то методы, объявленные в интерфейсе, в классе отсутствуют, а вместо них стоит некая «заглушка».
Скажем, если будем использовать ссылку на интерфейс, то сможем получить доступ к объявленному по умолчанию члену. Но допустим нам не требуется этот функционал, в таком случае нам не нужна ни реализация, ни заглушка.
Ужас. Открыли дыру через которую хлынет поток гвнокода. А реально полезные фичи как всегда на потом.
Хочу операторы ==,<,+- у интерфейсов. Чтобы юзать синт сахар на них. Где?
абстрактные классы теперь ущемлены?
Я считаю что нет. Кажется что то подобное было у Макконнелла: если нам нужно только поведение, мы работаем с интерфейсами. Если нам также нужны и данные, выбор за абстрактными классами.
Что теперь отвечать на собеседовании о различиях интерфейса и абстрактного класса?

Ответьте, что наследование от интерфейса — это в терминах C++ наследование виртуальное, а от класса, в том числе и абстрактного, — невиртуальное.


Расскажите потом как прошло.

Properties можно таким образом объявлять в интерфейсах?
Да, вполне:
interface ICommand
    {
        // some action
        void exec();

        public void build(string description)
        {
            Description = description;
        }

        public string Description { get; set; }
    }
А если будет так:
interface ICommand
    {
       
        public string Description { get; set; }
    }


То в реализаторах нужно будет опять определять свойство?
Нет, так тоже пойдет )
Не пойдет, ругается:
 public interface ITestInterface1
    {
        public string Property1 { get; set; }
    }

    public class TestClass1 : ITestInterface1
    {
        
    }

CS0535 'TestClass1' does not implement interface member 'ITestInterface1.Property1'
Я бы ещё добавил (уточнил) что в интерфейсах теперь можно писать вложенные классы, в том числе другие интерфейсы.
А что там с C# 9. Когда он наконец превратиться в swift-o-kotlin?
Наверное этого не случится )
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации