C # - явные интерфейсы с наследованием? - PullRequest
9 голосов
/ 06 декабря 2009

Выход:
B-> Здравствуйте! из явного.

Разве это не должно быть:?
A-> Привет! из явного.

Почему явное приведение (IHello) вызова IHello.Hello () из класса A?

interface IHello
{
    void Hello();
}

class A : IHello
{

    public virtual void Hello()
    {
        Console.WriteLine("A->Hello!");
    }

    void IHello.Hello()
    {
        Console.WriteLine("A->Hello! from Explicit.");
    }
}

class B : A, IHello
{
    public override void Hello()
    {
        Console.WriteLine("B->Hello!");
    }

    void IHello.Hello()
    {
        Console.WriteLine("B->Hello! from Explicit.");
    }
}

class Program
{
    static void Main(string[] args)
    {
        A a = new B();
        ((IHello)a).Hello();
    }
}

Ответы [ 4 ]

20 голосов
/ 06 декабря 2009

Нет, не должно.

Вызов Hello эквивалентен закомментированному - маршрут для получения IHello не имеет значения (если только он не требует проверки или преобразования во время выполнения); тип времени компиляции просто IHello в любом случае, и отображение интерфейса такое же, как и у вас.

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

Из раздела 13.4.4 спецификации C # 3.0:

Отображение интерфейса для класса или структура C находит реализацию для каждый член каждого интерфейса указанный в списке базовых классов C. Реализация конкретного Член интерфейса I.M, где я интерфейс, в котором член М является заявлено, определяется экспертизой каждый класс или структура S, начиная с С и повторяя для каждого последующего базовый класс C, пока совпадение находится:

  • Если S содержит объявление явного члена интерфейса реализация, которая соответствует I и M, тогда этот член является реализацией И.М.
  • В противном случае, если S содержит объявление нестатического открытого члена, совпадающего с M, то этот член является реализацией IM. Если более одного члена совпадает, то неизвестно, какой элемент является реализацией IM. происходят, если S является составным типом, где два члена, объявленные в универсальном типе, имеют разные сигнатуры, но аргументы типа делают их сигнатуры идентичными.
3 голосов
/ 06 декабря 2009

(A) ничего не делает. Ссылка уже объявлена, так что приведение к A не будет иметь никакого эффекта.

Даже если ваша ссылка объявлена ​​как A, объект, на который она ссылается, относится к типу B. Если вы приведете этот объект к IHello, вызов Hello () вызовет явную реализацию объекта B для Hello.

Выходная информация точно соответствует ожидаемой.

0 голосов
/ 06 декабря 2009

Нет, не должно.

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

При создании экземпляра класса B фактический тип объекта - B. Причина, по которой он печатает "This is class A.", заключается в том, что вы не переопределили метод ToString в классе B, вы скрыли его с помощью ключевого слова new. Поэтому класс B имеет два метода ToString, один унаследован от класса A, а другой скрывает его. Если вы используете ссылку A для вызова метода ToString, вызывается унаследованный метод, но если бы вы использовали ссылку B для его вызова, был бы вызван метод теневого копирования с выводом "This is class B.".

Также, если вы переопределяете метод ToString в классе B вместо его теневого копирования, он выведет "This is class B." независимо от типа ссылки.

0 голосов
/ 06 декабря 2009

Нет, когда вы создаете новый метод (ToString), он не является виртуальным. Новый просто означает, что вы не возражаете против того, чтобы он «скрывал» версию в базовом классе - поэтому, если вы вызываете его со ссылкой, которую вы привели к определенному типу (A), он выполняет метод в классе A, независимо от того, фактический тип объекта, который вы вызываете. (то есть вы вызвали A.ToString (), поэтому он выполнил A.ToString ())

Когда вы создаете виртуальный метод, то независимо от того, к какому типу вы приводите ссылку, используется реализация из фактического типа объекта (т. Е. Вы создали B, поэтому при вызове ( каким бы ни был объект). Здравствуйте, он называется Б. Привет)

Принципиальное отличие состоит в том, что один вызов является виртуальным, а другой - нет.

...