我正在学习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#中实现这种行为(即限制继承)?
[编辑]
澄清:我正在阅读的书中的部分是关于隐式和显式接口实现的细微差别和潜在问题 - 所以我明白了。此外,代码片段(从本书中复制)是故意冗长的,以便解释由于调用在基类中隐式实现的重新实现的成员方法而导致的不同语义(phew!)。
我的主要问题可简单概括为:
可以这样:
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继承的?
答案 0 :(得分: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
答案 1 :(得分: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
答案 2 :(得分:1)
RichTextBox
不必明确指定IUndoable
。像ReSharper这样的工具甚至可能会告诉你并提供删除。
AFAIK对继承没有限制,只是“默认”继承。
如果您不希望某人从您的班级派生,请将其设为sealed
。
答案 3 :(得分: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未在父类中定义为虚拟,这意味着它不会被覆盖,我们通过引入这个新方法来破坏继承层次结构。
答案 4 :(得分: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"); }
}
答案 5 :(得分:0)
你是对的。 RichtTextBox
也没有必要实现IUndoable
。您可以看到编译器也不是很开心,因为Undo
中的RichTextBox
方法隐藏了TextBox的Undo
方法(请参阅new
关键字)
子类应该实现它的基类接口的唯一原因是,当这些类是ComVisible时,你也希望将该接口暴露给COM。