Интерфейс C # и вопрос наследования - PullRequest
5 голосов
/ 18 мая 2011

Я изучаю C # (фон C ++), и я наткнулся на этот кусок кода:

public interface IUndoable { void Undo(); }
public class TextBox : IUndoable
{
    void IUndoable.Undo() { Console.WriteLine ("TextBox.Undo"); }
}

public class RichTextBox : TextBox, IUndoable
{
    public new void Undo() { Console.WriteLine ("RichTextBox.Undo"); }
}

Поскольку RichTextBox является производным от TextBox, кто-нибудь может объяснить, почему RichTextBox также происходит от IUndoable ?.Я бы подумал, что интерфейс IUndoable будет «унаследован» вместе с любыми другими членами TextBox, к которым имеет доступ RichTextBox?

В качестве отступления, я предполагаю из того, что я прочитал до сих пор, что концепцияпубличное, защищенное и частное наследование не существует в C #.

Это правильный вывод ?.Если да, то как такое поведение (то есть ограничение наследования) может быть реализовано в C #?

[Edit]

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

Мой основной вопрос можно просто сформулировать так:

Может ли это быть:

public class RichTextBox : TextBox, IUndoable
{
    public new void Undo() { Console.WriteLine ("RichTextBox.Undo"); }
}

Написано так:

public class RichTextBox : TextBox
{
    public new void Undo() { Console.WriteLine ("RichTextBox.Undo"); }
}

И если да, то почему авторбыть многословным (у него должна быть причина, я уверен).Если нет, то почему интерфейс не наследуется от TextBox?

Ответы [ 6 ]

6 голосов
/ 18 мая 2011

В C # для классов существует только эквивалент публичного наследования в C ++.

Однако вы можете реализовать интерфейс явно или неявно . TextBox реализует IUdoable явно, поэтому у вас есть

void IUndoable.Undo() 

вместо простого

void Undo() 

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

TextBox tb = new TextBox();
tb.Undo(); // error
((IUndoable)tb).Undo(); // ok

Интерфейсы, как вы говорите, "наследуются", но RichTextBox неявно реализует IUndoable, поэтому вам не нужно приведение для доступа к методам интерфейса:

RichTextBox rtb = new RichTextBox();
rtb.Undo(); // ok
2 голосов
/ 29 июля 2011

Быстрый пример показывает разницу.

interface IUndoable
{
    void Undo();
}

class TextBox : IUndoable
{
    void IUndoable.Undo()
    {
        Console.WriteLine("TextBox.Undo");
    }
}

class RichTexBox : TextBox
{
    public new void Undo()
    {
        Console.WriteLine("RichTextBox.Undo");
    }
}

class FilthyRichTextBox : TextBox, IUndoable
{
    public new void Undo()
    {
        Console.WriteLine("FilthyRichTextBox.Undo");
    }
}

Запустите следующее:

IUndoable text = new TextBox();
IUndoable richText = new RichTexBox();
IUndoable filthyRichText = new FilthyRichTextBox();

Console.WriteLine("From the TextBox:");
text.Undo();

Console.WriteLine("From the RichTextBox:");
richText.Undo();

Console.WriteLine("From the FilthyRichTextBox:");
filthyRichText.Undo();

Вот результаты:


Из TextBox:
TextBox.Undo
Из RichTextBox:
TextBox.Undo
Из FilthyRichTextBox:
FilthyRichTextBox.Undo

1 голос
/ 18 мая 2011

RichTextBox не нужно было бы явно указывать IUndoable. Такой инструмент, как ReSharper, вероятно, даже скажет вам об этом и предложит удалить.

И у AFAIK нет ограничений на наследование, просто наследование по умолчанию.

Если вы не хотите, чтобы люди ушли из вашего класса, сделайте его sealed.

0 голосов
/ 05 июня 2011

Ты прав. Не обязательно, чтобы RichtTextBox также реализовывал IUndoable. Вы можете видеть, что компилятор тоже не очень доволен, поскольку метод Undo в RichTextBox скрывает метод Undo TextBox (см. Ключевое слово new).

Единственная причина, по которой подкласс должен также реализовывать интерфейс своего базового класса, - это когда эти классы являются ComVisible, и вы хотите также представить этот интерфейс для COM.

0 голосов
/ 18 мая 2011

Да, может быть, его тоже скомпилируют

public class IUndoable
{
}
public class TextBox : IUndoable
{
   public new void Undo() { Console.WriteLine ("RichTextBox.Undo"); }
}

public class RichTextBox : TextBox
{
  public new void Undo() { Console.WriteLine ("RichTextBox.Undo"); }
}
0 голосов
/ 18 мая 2011

На самом деле RichTextBox представляет новое поведение для метода Undo вместо его переопределения (новое ключевое слово показывает это), таким образом, если доступ к RichTextBox осуществляется с использованием его интерфейса по умолчанию, этот метод будет выполнен, но если к нему обращается с помощью его родительского интерфейса, метод Undo TextBox будет выполнено .RichTextBox реализует IUndoable явно, поэтому, если кто-то хочет достичь этого класса с помощью интерфейса IUndoable, будет выполнен новый метод. В итоге:

var obj=new RichTextBox();

    obj.Undo(); // hits the new method  
    ((TextBox)obj).Undo(); //hits the parent (old) method.
    ((IUndoable)obj).Undo(); //hits the new method if RichTextBox implements IUndoable and otherwise hits the old method

Это не очень хороший подход, поскольку, поскольку Undo не был определен как виртуальный в родительском классе, это означает, что он не предназначен для переопределения, и мы нарушаем иерархию наследования, вводя этот новый метод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...