Почему класс C # может наследоваться от одного интерфейса как явно, так и явно? - PullRequest
16 голосов
/ 31 октября 2008

Сегодня я обнаружил, что один класс C # может наследовать один интерфейс как неявным, так и явным образом. Это удивляет меня. Если C # работает таким образом, то один экземпляр может вести себя по-разному, если на него ссылаются по-другому.

interface IFoo
{
    void DoSomething();
}

class Foo : IFoo
{
    #region IFoo Members
    public void DoSomething()
    {
        Console.WriteLine("do something implicitly");
    }
    #endregion

    #region IFoo Members
    void IFoo.DoSomething()
    {
        Console.WriteLine("do something explicitly");
    }
    #endregion
}


        Foo f = new Foo();
        f.DoSomething();

        ((IFoo)f).DoSomething();

Выше указанного кода выполняется и выводится

do something implicitly
do something explicitly

Я считаю, что этот дизайн C # делает несогласованность поведения. Возможно, обязательно, чтобы один класс C # мог наследовать от одного интерфейса неявным или явным образом, но не оба.

Есть ли причина, по которой C # спроектирован таким образом?

Ответы [ 5 ]

13 голосов
/ 31 октября 2008

Каждый класс, который реализует интерфейс, имеет отображение между членами этого класса и членами интерфейса. Если класс явно реализует элемент интерфейса, то явная реализация будет всегда отображаться на интерфейс. Если явной реализации нет, то ожидается неявная реализация, которая будет отображена в интерфейсе.

Когда класс имеет то же имя члена и связанные с ним типы, что и интерфейс , но , он также явно реализует соответствующий член для интерфейса, тогда "неявная" реализация класса не является рассматривается реализация интерфейса на всех (если явная реализация не вызывает его).

В дополнение к различным значениям в каждом случае, когда класс реализует несколько интерфейсов с одним и тем же именем / типом члена, даже с одним интерфейсом, сам класс считается имеющим неявный интерфейс, который может иметь тот же элемент / типы, что и в единственном интерфейсе, но все же означает что-то другое.

11 голосов
/ 31 октября 2008

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

7 голосов
/ 31 октября 2008

Это делает его более гибким, когда происходят столкновения. В частности, посмотрите на IEnumerator и IEnumerator<T> - они оба имеют свойство Current, но разных типов. У вас есть , чтобы использовать явную реализацию интерфейса для реализации обоих (и универсальная форма расширяет неуниверсальную форму).

2 голосов
/ 31 октября 2008

Множественное наследование: Что если вы производите от двух интерфейсов, определяющих один и тот же метод для разных целей?

  interface IMoveable
  {
    public void Act();
  }

  interface IRollable
  {
    public void Act();
  }

  class Thing : IMoveable, IRollable
  {
    //TODO Roll/Move code here

    void IRollable.Act()
    {
      Roll();
    }

    void IMoveable.Act()
    {
      Move();
    }
  }
0 голосов
/ 31 октября 2008

Ребята, спасибо за ваши ответы.

Оказывается, что «класс C # может наследовать один интерфейс как неявным, так и явным образом одновременно», на самом деле является иллюзией. Фактически, один класс может наследовать один интерфейс за один раз.

В первоначальном вопросе метод «DoSomething» кажется «неявно реализующим» интерфейс IFoo (метод фактически генерируется VS2008), но на самом деле это НЕ. При явной реализации интерфейса IFoo метод «DoSomething» превращается в обычный метод, который не имеет ничего общего с IFoo, за исключением той же сигнатуры.

Я все еще считаю, что это хитрый дизайн C #, и его легко ошибочно использовать. Скажем, у меня есть такой код

        Foo f = new Foo();
        f.DoSomething();

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

        Action<IFoo> func = foo => foo.DoSomething();
        func(f);
...