【问题标题】:C# interface and inheritance questionC#接口和继承问题
【发布时间】:2011-05-18 07:03:20
【问题描述】:

我正在学习 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 接口将与 RichTextBox 有权访问的任何其他 TextBox 成员一起“继承”?

顺便说一句,根据我目前所读到的内容,我猜测 C# 中不存在公共、受保护和私有继承的概念。

这是一个正确的推论吗?如果是这样,这种行为(即限制继承)如何在 C# 中实现?

[编辑]

澄清:我正在阅读的书中的部分是关于隐式和显式接口实现的细微差别和潜在陷阱 - 所以我明白了。此外,代码 sn-p(从书中复制)是故意冗长的,以便解释由于调用在基类中隐式实现的重新实现的成员方法而产生的不同语义(呸!)。

我的主要问题可以简单概括为:

这样可以吗:

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?

【问题讨论】:

标签: c# inheritance interface


【解决方案1】:

在 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】:

    运行一个简单的示例会显示差异。

    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();
    

    结果如下:


    来自文本框:
    文本框.撤消
    来自 RichTextBox:
    文本框.撤消
    来自 FilthyRichTextBox:
    FilthyRichTextBox.Undo

    【讨论】:

      【解决方案3】:

      RichTextBox 不必明确指定 IUndoable。像 ReSharper 这样的工具甚至可能会告诉您并提供删除功能。

      而且 AFAIK 对继承没有限制,只是“默认”继承。

      如果您不希望人们从您的类派生,请将其设为 sealed

      【讨论】:

        【解决方案4】:

        实际上 RichTextBox 为 Undo 方法引入了一种新行为,而不是覆盖它(新关键字显示了这一点),因此如果使用其默认接口访问 RichTextBox,则将执行此方法,但如果使用其父接口访问它,则使用 TextBox 的 Undo 方法将被执行。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 在父类中没有被定义为虚拟,这意味着它不打算被覆盖,我们通过引入这个新方法打破了继承层次结构。

        【讨论】:

          【解决方案5】:

          是的,它也可以编译

          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"); }
          }
          

          【讨论】:

            【解决方案6】:

            你是对的。 RichtTextBox 也没有必要实现 IUndoable。你可以看到编译器也不是很满意,因为RichTextBox 中的Undo 方法隐藏了TextBox 的Undo 方法(参见new 关键字)。

            子类也应该实现其基类的接口的唯一原因是,当这些类是 ComVisible 时,您也想将该接口公开给 COM。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-07-31
              • 2011-06-14
              • 2021-08-10
              • 1970-01-01
              • 2021-06-24
              相关资源
              最近更新 更多