В 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
}
}