В C# 8.0 есть способ раскрыть реализацию члена по умолчанию в классе?

В C# 8.0 интерфейсы могут иметь реализации по умолчанию для некоторых членов. Эти реализации являются явными, что означает, что они недоступны через экземпляр класса, и мы должны привести к типу интерфейса, чтобы вызвать их. Есть ли способ предоставить эту реализацию в экземпляре класса с тем же именем? Его можно открыть под другим именем, приведя указатель this к типу интерфейса и вызвав метод, например:

void A()
{
   ((ISomething)this).B();
}

Однако я не могу найти способ раскрыть реализацию с исходным именем B, потому что, если я объявляю метод B, он считается тем, который реализует интерфейс, вызывающий бесконечную рекурсию. Есть ли способ раскрыть реализацию, не копируя ее, или мне что-то не хватает?

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

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

2 ответа

Решение

Нет простого способа сделать это; возможны различные уродливые обходные пути, которые все сводятся к делегированию некоторому другому методу (статическому методу или использованию вспомогательного класса, который сам не реализовал метод) для доступа к нему, и даже тогда вам нужно каким-то образом передать состояние. Есть предложение поbase(T)синтаксис, здесь черновик спецификации, который должен позволятьbase(ISomething).B()для ссылки на реализацию, не вызывая циклической ссылки. Изначально планировалось, что это будет частью C# 8, но это оказалось слишком амбициозным, и его урезали. На момент написания он был кандидатом на включение в C# 9.

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

class Something : IInterfaceA, IInterfaceB {
   public IInterfaceA A => this;
   public IInterfaceB B => this;
}

...

something.A.AMethod();
something.B.BMethod();

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

interface IInterface {
}

static class IInterfaceExtensions {
   public static void DoSomething(
      this IInterface me
   ) {
      // do something
   }
}
Другие вопросы по тегам