Явная реализация интерфейса не может быть виртуальной

Для протокола, я уже видел этот элемент подключения, но я не могу понять, в чем проблема с его поддержкой.

Скажем, у меня есть следующий код:

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 Явные реализации интерфейса) есть две причины.

  1. Скрытие определенных методов (для которых я использую это).
  2. Наличие 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???
    }
}

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

Другие вопросы по тегам