开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜