powered by simpleCommunicator - 2.0.36     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Default interface methods (C# 8)
25 сообщений из 25, страница 1 из 1
Default interface methods (C# 8)
    #40065735
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Используете ли?
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40065764
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fkthat,

норм фича
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40065770
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVostt
fkthat,

норм фича

21962407
hVostt
ЕвгенийВ,

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

MS за прошедшие с тех пор полтора года успел что-то сильно переделать в этой фиче?
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40065848
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVostt,

Мне сама идея не особо как-то сначала понравилась. Но есть очень типичная ситуация, когда для удобства хочется в интерфейсе иметь больше методов, но при этом большая их часть всегда и везде будет реализовываться просто через другие методы того же интерфейса. И типовым решением для этого было использовать методы-расширения - можно посмотреть, например, как устроены интерфейсы IServiceProvider или ILogger - в них самих всего по одному методу, а все остальные "их" методы это методы-расширения. (Я сам не большой любитель расширений, но вот это, как раз случай, где расширения подходят просто идеально.) И вот, я подумал, что DIM в таких случаях могут быть удобной альтернативой:

1) Нет риска поломки из-за конфликта с "обычным" методом.
2) Нет зависимости от наличия using.
3) Можно определять свойства.

Попробовал заменять расширения дефолтными методами и сразу же наткнулся на проблемы:

1) Дефолтный метод доступен только через интерфейс, но не через класс, который этот интерфейс реализует (точь в точь как explicit method implementation). Обычно это проблем вызывать не должно, т.к. DI и все используется через интерфейсы. Но, есть, все-таки, ситуации когда это может быть проблемой. Допустим, я пишу какой-то библиотечный класс и просто не хочу закладываться на то, что тот, кто его будет использовать обязательно будет использовать его через интерфейс, а не напрямую.

2) Моки. Вот это проблема уже настоящая. Castle (по крайней мере в текущей версии) не может создавать dynamic proxy для интерфейсов с дефолтными методами. Нашел в итоге обходной путь:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
public interface IFoo
{
    string Name {get;}

    string Hello => $"Hello, {Name}!";
}

// вспомогательная пустая реализация IFoo для тестов
public abstract class TestingFoo: IFoo
{
    public abstract string Name { get; }
}

[Fact]
public void Hello_ShouldReturnHelloName()
{
    // создаём мок не для самого интерфейса, а для его вспомогательной реализации
    // переменная объявляется явно как IFoo, потому что DIM доступны только при вызове через интерфейс
    IFoo foo = A.Fake<TestingFoo>();
    A.CallTo(() => foo.Name).Returns("World");
    foo.Hello.Should().Be("Hello, World!");
}



Так работает, но вся конструкция в целом несколько уродливая, все это приходится делать везде где нужен мок для IFoo, и всегда надо помнить что IFoo (и другие подобные) надо мокать не напрямую, а только через вспомогательную абстрактную реализацию.

В общем, покрутил я все это так и сяк, и, в том, что касается того о чем я сначала писал (заменить методы-расширения дефолтными реализациями) вернулся все-таки к старым добрым расширениям.

И еще, с т.з. идеологии. Само по себе наличие у метода интерфейса реализации по-умолчанию это вполне нормально, почему бы и нет. Но синтаксически все это сделано как-то некрасиво. Интерфейс, по своей сути, это просто спецификация какого-то public API компонента. И смешивать её с кодом реализации смотрится как-то не очень. Это как если бы в файл OpenAPI сваггера можно было бы вписать какой-нибудь код на PHP с реализацией описанного там вызова :)
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40065856
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fkthat
1) Дефолтный метод доступен только через интерфейс, но не через класс, который этот интерфейс реализует (точь в точь как explicit method implementation). Обычно это проблем вызывать не должно, т.к. DI и все используется через интерфейсы. Но, есть, все-таки, ситуации когда это может быть проблемой. Допустим, я пишу какой-то библиотечный класс и просто не хочу закладываться на то, что тот, кто его будет использовать обязательно будет использовать его через интерфейс, а не напрямую.
А в чем тут проблема-то, я не понял. Если реализация есть, то она и будет использоваться, если нет, подтянется из интерфейса. Какая разница, через что это будет использоваться потребитель? это совсем не то же самое, что explicit method implementation
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40065871
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Shocker.Pro
А в чем тут проблема-то, я не понял. Если реализация есть, то она и будет использоваться, если нет, подтянется из интерфейса. Какая разница, через что это будет использоваться потребитель?

Вот в чем. Возьмем интерфейс из моего примера выше и его реализацию:
Код: c#
1.
2.
3.
4.
public class Foo: IFoo
{
    public string Name => "World";
}


А теперь, допустим, что это часть библиотеки, которую использует кто-то другой. И такой код:
Код: c#
1.
2.
Foo foo = new();
Console.WriteLine(foo.Hello);

у него вообще не соберется. Т.е. надо будет либо указывать в доках (которые никто не читает :), что писать можно только так:
Код: c#
1.
2.
IFoo foo = new Foo();
Console.WriteLine(foo.Hello);

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

Shocker.Pro
это совсем не то же самое, что explicit method implementation

Я это знаю. Я и имел в виду не "то же самое" а "ведет себя так же в плане доступа к методу".
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40065881
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А, дошло, да, такие кейсы я не использовал... за ненадобностью )))
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40066002
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
получается, в C# подвезли множественное наследование "абстрактных классов"?
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40066018
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtes
получается, в C# подвезли множественное наследование "абстрактных классов"?

Нет. Но это близко к "traits".
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40066067
Фотография ЕвгенийВ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fkthat,
Еще так работает.

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
    public interface IFoo
    {
        string Name { get; }

        string Hello => $"Hello, {Name}!";
        static void Main(string[] args)
        {
            Console.WriteLine("Привет мир");
        }
    }
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40066098
Фотография Где-то в степи
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну очевидно удобная штука, в каком контексте ( если судить по джаве)
вы пишете что то большое и монструозное, промышленный интерфейс с кучей методов, ну типа орм.
Проходит время нужно добавить ряд методов, вы добавляете в интерфейс и бац. компиляция не проходит, просит их реализовать в наследниках.
рутина (((( ты начинаешь рвать волосы еююй интерфейс обыкновенный класс с виртуалами ума хватило у разрабов.
а тут бац default по месту обявления и в шеколаде. ( я думаю они так и сперли)
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40066109
Фотография ЕвгенийВ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Где-то в степи
( я думаю они так и сперли)

это жаба обычно спирает, посмотрите на атрибуты или LINQ
тут задел на будущее, в ближайших версиях .NET станет возможна прямая с жабой, последняя будет подключаться как либа с возможностью использовать все как есть, можно например отнаследоваться от жаба класса будет
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40066114
Фотография Где-то в степи
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ЕвгенийВ,
скрестить ежа с жабой, скрепьненько )) тырят труг у друга помаленьку, а вот деревья выражений слабовато, а была бы революция в языке. скучноватый язык ( хоть и пишу на нем последние 5 лет - не мало)
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40066123
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtes
получается, в C# подвезли множественное наследование "абстрактных классов"?
Нет, потому что у интерфейса нет состояния
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40066136
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Где-то в степи
вы пишете что то большое и монструозное, промышленный интерфейс с кучей методов, ну типа орм. Проходит время нужно добавить ряд методов, вы добавляете в интерфейс и бац. компиляция не проходит, просит их реализовать в наследниках.

Если все это свой собственный проект, то:

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

2) Если же мы решаем проблему из п.1 через DIM, то мы сразу же переносим её на юнит-тесты, в которых интерфейс мокается (как я писал выше). Все юнит-тесты которые мокают этот интерфейс сразу же поломаются.

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

Сценарий, например, такой:

1) Вася создал мегафреймворк "Foo" в котором есть интерфейс IFoo для его расширения и публикует его как NuGet пакет Foo с версией 1.0.0.

2) Петя цепляет версию Foo.1.0.0 в свою либу Bar, реализует в ней свой компонент-расширение с интерфейсом IFoo, и публикует свое творение как Bar.1.0.0.

3) Васин фреймворк очень успешен, у него куча идей по его развитию, и он добавляет к своему интерфейсу IFoo еще один метод. Вася успешный инвестор опытный разработчик соблюдающий заветы SemVer, поэтому, зная, что изменение интерфейса может поломать совместимость, увеличивает мажорную версию, и свое новое произведение публикует уже как Foo.2.0.0. У Пети с этим проблем нет, потому что его пакет зависит от версии Foo.1.0.0 где интерфейс еще прежний.

4) А вот теперь мы в своем проекте цепляем одновременно либу Пети Bar.1.0.0 и фреймворк Васи Foo.2.0.0 (мы же хотим быть на острие прогресса и берем все самое последнее). И вот как раз тогда у нас все действительно падает.

Но такой сценарий, все-таки, не отнесешь к тому, с чем каждый день сталкиваешься.
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40066137
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Shocker.Pro
Нет, потому что у интерфейса нет состояния

fkthat
Нет. Но это близко к "traits".
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40066146
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры Павловны
hVostt
fkthat,

норм фича

21962407
hVostt
ЕвгенийВ,

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

MS за прошедшие с тех пор полтора года успел что-то сильно переделать в этой фиче?


Неожиданно нашли ей применение при рефакторинге и особенно в библиотечных компонентах.
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40066148
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fkthat
1) Дефолтный метод доступен только через интерфейс, но не через класс, который этот интерфейс реализует (точь в точь как explicit method implementation). Обычно это проблем вызывать не должно, т.к. DI и все используется через интерфейсы. Но, есть, все-таки, ситуации когда это может быть проблемой. Допустим, я пишу какой-то библиотечный класс и просто не хочу закладываться на то, что тот, кто его будет использовать обязательно будет использовать его через интерфейс, а не напрямую.


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

Чем это лучше расширений? Тем, что дефолтные методы интерфейса можно имплементировать, а расширения -- нет.

fkthat
2) Моки. Вот это проблема уже настоящая. Castle (по крайней мере в текущей версии) не может создавать dynamic proxy для интерфейсов с дефолтными методами. Нашел в итоге обходной путь:


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

Это как методы расширения, только в ряде случаев лучше. Сложной логики там быть не должно. Обычно рутинное приведение, или вариации для удобного использования. Никакой логики.
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40066150
Фотография Где-то в степи
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fkthat,
судя по изложенному, этот проблема называется diamond, не проверял, но имхо компилятор пошлет вас нах, и будет требовать
явный вызов, и вообще это сразу оговривалось при презентации этих фитч, и статус у них - компромисный в контесте оп.
тоже самое и статик..
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40066155
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVostt
Дефолтные методы как раз мокаются на ура.

Нет. На практике проверено. И проблема упирается как раз в Кастел (который все мок-фреймворки используют). В крайней версии Moq какой-то workaround уже встроили, но, вот, в FakeItEasy (кторым я как раз и пользуюсь) этого еще нет - по обсуждению в issues их позиция - "подождем, пока это будет поддерживаться нативно в Castle".

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

Впрочем, ты, м.б. о том, что руками они "мокаются на ура" - но ведь это же совсем колхоз-совхоз :))
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40066158
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVostt
Это как методы расширения, только в ряде случаев лучше.

Да, я об этом и написал, но, как видишь, там свои проблемы при этом возникают.

hVostt
Насчёт динамик прокси, если тебе это нужно, то скорее всего ты используешь их неправильно.

Я их не использую сам, но их используют мок-фреймворки. Проблема с ними. Вот такой код сразу же кидает ексепшен:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
public interface IFoo
{
    string Name {get;}

    string Hello => $"Hello, {Name}!";
}

[Fact]
public void Hello_ShouldReturnHelloName()
{
    var foo = A.Fake<IFoo>();
    A.CallTo(() => foo.Name).Returns("World");
    foo.Hello.Should().Be("Hello, World!");
}


Как обойти я уже в самом начале писал, но мне такой способ не по душе - не очень как-то красиво выглядит.
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40066163
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVostt,

Что обидно, с Moq моки работают. Вот это вот вполне ок:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
[Fact]
public void Hello_ShouldReturnHelloName()
{
    var fooMock = new Mock<IFoo>();
    fooMock.Setup(m => m.Name).Returns("World");
    fooMock.Setup(m => m.Hello).CallBase();
    fooMock.Object.Hello.Should().Be("Hello, World!");
}


Но, я, вот, Moq уже разлюбил и полюбил вместо него FakeItEasy за намного более компактный синтаксис.
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40067015
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fkthat
Впрочем, ты, м.б. о том, что руками они "мокаются на ура" - но ведь это же совсем колхоз-совхоз :))


Эм.. ну погоди. Дефолтные методы как раз мокать не обязательно, ты мокаются те методы, которые они используют. Т.е. тут трагической проблемы нет :)

Давай ситуёвину представим. Ты мокаешь свой интерфейс, а компонент юзает интерфейс через экстеншен методы. Пральна? Ты ж не можешь это замокать. То на то и выходит.

Но можно и руками. В любом случае возможностей больше, чем с экстеншенами :)
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40067017
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fkthat
Я их не использую сам, но их используют мок-фреймворки. Проблема с ними. Вот такой код сразу же кидает ексепшен:


аа... ну да, проблема понятна. придётся ждать, когда подтянутся.
...
Рейтинг: 0 / 0
Default interface methods (C# 8)
    #40067018
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fkthat
Но, я, вот, Moq уже разлюбил и полюбил вместо него FakeItEasy за намного более компактный синтаксис.


по мне так однофигственно :)
...
Рейтинг: 0 / 0
25 сообщений из 25, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Default interface methods (C# 8)
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]