.NET C # Явная реализация метода интерфейса дедушки в родительском интерфейсе. - PullRequest
6 голосов
/ 21 декабря 2010

Это заглавие, не правда ли? ...

Вот что я пытаюсь сделать:

public interface IBar {
     void Bar();
}
public interface IFoo: IBar {
    void Foo();
}
public class FooImpl: IFoo {
    void IFoo.Foo()   { /* works as expected */ }
    //void IFoo.Bar() { /* i'd like to do this, but it doesn't compile */ }

    //so I'm forced to use this instead:
    void IBar.Bar()   { /* this would compile */ }
}

Моя проблема в том, что это ...неудобно вызывать Bar ():

IFoo myFoo = new FooImpl();
//myFoo.Bar(); /* doesn't compile */
((IBar)myFoo).Bar(); /* works, but it's not necessarily obvious 
                        that FooImpl is also an IBar */

Итак ... Есть ли способ объявить IFoo.Bar(){...} в моем классе, кроме как объединение двух интерфейсов в один?

А если нет, то почему?

Ответы [ 6 ]

5 голосов
/ 21 декабря 2010

Можно использовать ключевое слово new в интерфейсе для явного скрытия члена, объявленного в расширяемом интерфейсе:

public interface IBar
{
    void Bar();
}

public interface IFoo:IBar
{
    void Foo();
    new void Bar();
}

public class Class1 : IFoo
{
    void Bar(){}

    void IFoo.Foo(){}

    void IFoo.Bar(){}

    void IBar.Bar(){}
}
1 голос
/ 21 декабря 2010

Это просто соглашение компилятора для явно реализованных методов интерфейса. Вы могли бы написать это так:

public class FooImpl : IFoo {
    public void Foo() { /* implements IFoo.Foo */ }
    public void Bar() { /* implements IBar.Bar */ }
}

Но если вы хотите использовать явную реализацию, то компилятор настаивает на том, чтобы вы использовали имя идентификатора интерфейса, который объявил метод. Что имеет смысл, IFoo также может иметь метод Bar ().

1 голос
/ 21 декабря 2010

Что бы вы хотели, чтобы поведение было? Всякий раз, когда вы вызываете IFoo.Bar(), оно будет использовать определение в IBar, потому что это просто интерфейс и не имеет никакой отдельной концепции Bar(). Вы можете иметь другой метод, вызываемый только при приведении к суперклассу с ключевым словом new , и именно тогда вы переопределяете метод в классе, но не реализуете и не взаимодействуете.

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


Осторожно: возможное чрезмерное осложнение и разрушение мозга !!! Читайте с осторожностью !!!

Я считаю, что это разрешено, поправьте меня, если я ошибаюсь:

public class IBar {
     virtual void Bar() {
         //IBar implementation of Bar
     }
}
public class IFoo: IBar {
    new virtual void Foo() {
        //implementation of Foo when currently casted to IFoo
    }
}
public class FooImpl: IFoo {
    new void Foo()   { /* implementation of Foo when cast to FooImpl */ }
    new void Bar()   { /* implementation of Bar when cast to FooImpl */ }
}

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

IBar b = new IBar();
b.Bar(); //calls IBar.Bar

IFoo f = new IFoo();
f.Bar(); //calls IFoo.Bar
f.Foo(); //calls IFoo.Foo
IBar fooAsBar = (IBar) f;
fooAsBar.Bar(); //calls IBar.Bar

FooImpl fi = new FooImpl();
fi.Bar(); //calls FooImpl.Bar
fi.Foo(); //calls FooImpl.Foo 
IFoo fooImplAsFoo = (IFoo) fi;
fooImplAsFoo.Bar(); //calls IFoo.Bar
fooImplAsFoo.Foo(); //calls IFoo.Foo
IBar fooImplAsBar = (IBar) fi;
fooImplAsBar.Bar(); //calls IBar.Bar

О, и вы не используете вложенные интерфейсы, они просто наследуются друг от друга. Вложенные интерфейсы выглядят так:

interface IBar {
    void Bar();

    interface IFoo {
        void Foo();
    }
}

Как видите, это совсем другое. Связь между двумя интерфейсами только в том, что один может использоваться только внутри другого. Это сложная и несколько сложная тема. Вы можете узнать больше здесь . : D

1 голос
/ 21 декабря 2010

Поскольку IFoo расширяет Ibar, void IFoo.Bar() и void IBar.Bar() - это одна и та же функция. Вы не можете определить один и тот же метод дважды, поэтому он не работает.

1 голос
/ 21 декабря 2010

У вас нет двух реализаций IFoo;у вас есть только один.
CLR не различает копии интерфейсов, которые поступают из разных точек дерева интерфейсов.

В частности, нет способа вызвать IFoo.Bar();вы можете вызывать только IBar.Bar.
Если вы добавите отдельный метод Bar() к IFoo, ваш код будет работать.

0 голосов
/ 04 января 2011

Я тоже был разочарован этим раньше, но я думаю, что ключ кроется в том факте, что это, по определению, "явная" реализация.Если вы не приведете свой объект к IBar, то любой вызов метода Bar неявно зависит от того факта, что объект в конечном итоге реализует IBar.

Рассмотрите приведенный ниже пример как логическое завершение того, что вы хотите.Теоретически, FooImpl может явно реализовать Bar благодаря реализации IFoo, а теоретически, производный класс (FooChild) может реализовать IBar благодаря наследованию от FooImpl.Проблема в том, что это открывает возможность (как минимум) двух разных неоднозначных «явных» путей реализации:

public interface IBar {      void Bar(); } 
public interface IFoo: IBar {     void Foo(); }
public class FooImpl: IFoo {  
   void IFoo.Foo()   {  }     
   void IFoo.Bar()   { /* hypothetically, let's suppose this works */ }
   void IBar.Bar()   { /* this could then co-exist with the above.. */  } 
} 
public class FooChild : FooImpl
{
}

public class Owner
{
    public void Stuff()
    {
        FooChild child = new FooChild();
        // This invokes the "explicit" bar method (except not really...)
        ((FooImpl)child).Bar();     // Which version of Bar should be called here?
    }
}
...