C#接口和继承问题

5

我正在学习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#中实现此类行为(即限制继承)?
[编辑]
澄清一下:我正在阅读的书中的部分内容是关于隐式和显式接口实现的微妙差异和潜在陷阱 - 所以我明白了。此外,代码片段(从书中复制)是故意冗长的,以解释调用在基类中隐式实现的重新实现成员方法所产生的不同语义(呼!)。
我的主要问题可以简单地总结为:
这样做可以吗:
public class RichTextBox : TextBox, IUndoable
{
    public new void Undo() { Console.WriteLine ("RichTextBox.Undo"); }
}

Be written as:

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

如果是,为什么作者要这样冗长(我相信他一定有原因)。 如果不是,为什么接口没有从TextBox继承?


1
请参考 http://msdn.microsoft.com/en-us/library/ms173153(v=vs.80).aspx 了解何时使用 override 和 new 关键字。 - nickvane
6个回答

6

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

这里是结果:

从TextBox:
TextBox.Undo
从RichTextBox:
TextBox.Undo
从FilthyRichTextBox:
FilthyRichTextBox.Undo


1

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

据我所知,继承没有限制,只有“默认”继承。

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


0

是的,它可能是,它也正在被编译

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

实际上,RichTextBox为Undo方法引入了一种新的行为,而不是覆盖它(new关键字显示这一点)。因此,如果使用其默认接口访问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定义为虚拟函数,这意味着它不打算被重写,并且我们通过引入这个新方法来破坏了继承层次结构。


0

你说得对。 RichtTextBox 不一定也要实现 IUndoable 接口。你可以看到编译器也不是完全满意,因为 RichTextBox 中的 Undo 方法隐藏了 TextBox 的 Undo 方法(请参见 new 关键字)。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接