C# interface and inheritance question
I am learing C# (C++ background), and I have come accross this piece of code:
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"); }
}
Since RichTextBox derives from TextBox, can anyone explain why RichTextBox is also deriving from IUndoable?. I would have thought that the IUndoable interface will be "inherited along" with any other TextBox members that RichTextBox has access to?
As an aside, I am guessing from what I have read so far, that the concept of public, protected and private inheritance does not exist in C#.
Is this a correct inference?. If so, how may such behavior (i.e. restricting inheritance) be implemented in C#?
[Edit]
Clarification: The section in the book I am reading is about the subtle differences and potential gotchas of implicit and explicit interface implementations - so I get that. Also, the code snippet (copied from the book) is intentionally verbose, so as to explain the differing semantics that ensues as a result of invoking a reimplemented member method that was implicitly implemented in the base class (phew!).
My main question ca开发者_如何学Cn simply be summarized as:
Could this:
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"); }
}
And if yes, why is the Author being verbose (he must have a reason I'm sure). If no, why is the interface not being inherited from TextBox?
In C#, for classes, there is only the equivalent of public inheritance in C++.
You can, however, implement an interface explicitly or implicitly. TextBox implements IUdoable explicitly, that's why you have
void IUndoable.Undo()
instead of simply
void Undo()
in your TextBox
class. When an interface is implemented explicitly, you can access the interface's methods on the object only through an explicit cast:
TextBox tb = new TextBox();
tb.Undo(); // error
((IUndoable)tb).Undo(); // ok
Interfaces are, as you say, "inherited along", but RichTextBox re-implements IUndoable implicitly, so you don't need the cast to access the interface's methods:
RichTextBox rtb = new RichTextBox();
rtb.Undo(); // ok
Running a quick example shows the difference.
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");
}
}
Run the following:
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();
Here are the results:
From the TextBox:
TextBox.Undo
From the RichTextBox:
TextBox.Undo
From the FilthyRichTextBox:
FilthyRichTextBox.Undo
RichTextBox
would not have to specify IUndoable
explicitly. A tool like ReSharper would probably even tell you so and offer removal.
And AFAIK there is not restriction on inheritance, just “default” inheritance.
If you don't want people to derive from your class, make it sealed
.
Actually RichTextBox is introducing a new behavior for the Undo method instead of overriding it (new keyword shows this) thus if RichTextBox is accessed using its default interface this method will be executed but if it's accessed using its parent interface Undo method of TextBox will be executed .RichTextBox implements IUndoable explicitly so if anyone wants to reach this class using IUndoable interface the new method will be executed. In Summary:
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
This is not a good approach because since Undo has not been defined as virtual in parent class it means that it's not intended to be overrided and we are breaking the inheritance hierarchy by introducing this new method.
Yes it could be, its also getting compiled
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"); }
}
You're correct. It is not necessary that RichtTextBox
implements IUndoable
as well. You can see that the compiler isn't entirly happy as well, since the Undo
method in the RichTextBox
hides the Undo
method of the TextBox (see the new
keyword).
The only reason when a subclass should implement the interface of it's base class as well, is when those classes are ComVisible, and you want to expose that interface to COM as well.
精彩评论