Явная реализация интерфейса не может быть виртуальной
Для протокола, я уже видел этот элемент подключения, но я не могу понять, в чем проблема с его поддержкой.
Скажем, у меня есть следующий код:
public interface IInterface
{
void Method();
}
public class Base : IInterface
{
virtual void IInterface.Method()
{
throw new NotImplementedException();
}
}
В чем проблема с виртуальным идентификатором? Наличие виртуального модификатора позволило бы override
указывая, что есть другая реализация в базовом классе. Теперь я могу заставить его работать, удалив виртуальный метод и создав производный класс следующим образом:
public class Derived : IInterface
{
void IInterface.Method()
{
throw new NotImplementedException();
}
}
однако таким образом у меня действительно нет никаких признаков того, что я что-то переопределяю.
Обновить:
Согласно спецификации C# (часть: 20.4.1 Явные реализации интерфейса) есть две причины.
- Скрытие определенных методов (для которых я использую это).
- Наличие 2 функций с одинаковой сигнатурой, но разными типами возвращаемых данных (например, полезно для IClonable).
Однако ничего не говорится о том, почему вы не можете сделать эти методы виртуальными.
Update2:
Учитывая ответы, я думаю, что я должен перефразировать реальный вопрос здесь. Если вышеуказанные 2 причины являются причиной, по которой явная реализация интерфейсов стала возможной в первую очередь. Почему это будет проблемой, если вы сделаете метод виртуальным.
5 ответов
однако таким образом у меня действительно нет никаких признаков того, что я что-то переопределяю
Ну, вы делаете, вроде - у вас есть факт, что это явно явная реализация интерфейса. Это показывает, что он обеспечивает полиморфное поведение для этого вызова метода, который указан в интерфейсе... почему это имеет значение, реализует ли интерфейс базовый класс? Какая разница для вас, когда вы будете читать код?
Для меня главное преимущество изложения override
чтобы убедиться, что у меня действительно есть правильная подпись - что она соответствует тому, что я пытаюсь переопределить. Вы уже получили это преимущество с явной реализацией интерфейса, как если бы вы указали несуществующий метод или неверные параметры и т. Д., Компилятор уже будет жаловаться.
Я могу понять вашу точку зрения, но я никогда не находил это реальной проблемой.
Метод, реализующий интерфейс в явном виде, имеет специальную область видимости = вы не можете получить к нему доступ из другого метода, если вы не приведете "this" к целевому типу интерфейса. Я предполагаю, что это было причиной того, что виртуальный спецификатор не поддерживается - вы не можете переопределить метод, который не является частью обычного объектного интерфейса (private/protected/public).
Это мой обходной путь:
public class Base : IInterface
{
protected virtual void Method()
{
}
void IInterface.Method()
{
this.Method()
}
}
public class Derived : Base
{
protected override void Method()
{
}
}
Введя защищенный виртуальный / абстрактный метод, вы можете заставить его работать:
public interface IInterfaceA
{
void Method();
}
public interface IInterfaceB
{
void Method();
}
public class Base : IInterfaceA, IInterfaceB
{
void IInterfaceA.Method()
{
MethodA();
}
void IInterfaceB.Method()
{
MethodB();
}
protected virtual void MethodA()
{
Console.WriteLine("Called through base class interface A.");
}
protected virtual void MethodB()
{
Console.WriteLine("Called through base class interface B.");
}
}
public class Derived : Base
{
protected override void MethodB()
{
Console.WriteLine("Called through derived class interface B.");
}
}
Возможность иметь явные реализации интерфейса виртуальными была бы полезна только в одном сценарии: когда переопределение производного класса должно вызывать реализацию родительского класса. К сожалению, даже если бы явные реализации интерфейса можно было сделать виртуальными, у переопределяющего класса не было бы способа вызвать реализацию своего родителя, если бы для этого не было нового синтаксиса. VB.net прекрасно справляется с этим, позволяя объявлять метод, который реализует интерфейс Protected
с другим именем из метода интерфейса. Таким образом, производный класс может переопределить Protected
метод (используя соответствующее имя), и это переопределение может вызвать версию родительского класса (используя то же имя).
Если существует только один интерфейс, который наследуется, зачем вам это нужно:
public class Base : IInterface
{
virtual void IInterface.Method()
{
throw new NotImplementedException();
}
}
Почему бы просто не пойти
public class Base : IInterface
{
virtual void Method()
{
throw new NotImplementedException();
}
}
Я думаю, что причина может быть просто показана в следующем примере. Рассмотрим этот код:
public interface IInterfaceA
{
void Method();
}
public interface IInterfaceB
{
void Method();
}
public class Base : IInterfaceA, IInterfaceB
{
virtual void IInterfaceA.Method()
{
...
}
virtual void IInterfaceB.Method()
{
...
}
}
public class Derived : Base
{
public override void Method()
{
// Will this override IInterfaceA or IInterfaceB implementation???
}
}
Короче говоря, если вы явно реализуете несколько интерфейсов с одинаковой сигнатурой метода, ваши производные классы не будут знать, какой базовый метод вы хотите переопределить.