2011-05-18 32 views
5

estoy learing C# (C++ fondo), y he venido al otro lado de esta pieza de código:C# interfaz y la herencia pregunta

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

Desde RichTextBox deriva del cuadro de texto, puede alguien explicar por qué RichTextBox también se deriven de los IUndoable ?. Hubiera pensado que la interfaz IUndoable se "heredará junto" con cualquier otro miembro de TextBox al que RichTextBox tenga acceso.

Como un lado, estoy adivinando por lo que he leído hasta ahora, que el concepto de herencia pública, protegida y privada no existe en C#.

¿Es esto una inferencia correcta ?. Si es así, ¿cómo se puede implementar dicho comportamiento (es decir, restringir la herencia) en C#?

[Editar]

Aclaración: La sección en el libro que estoy leyendo es acerca de las diferencias sutiles y potenciales trampas de implementaciones de interfaz implícitos y explícitos - por lo que entiendo. Además, el fragmento de código (copiado del libro) es intencionalmente detallado, para explicar la semántica diferente que surge como resultado de invocar un método de miembro reimplementado que se implementó implícitamente en la clase base (¡phew!).

Mi pregunta principal simplemente se puede resumir como:

Podría esto:

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

escribirse como:

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

Y si es así, ¿por qué ser el autor prolijo (él debe tener una razón por la que estoy seguro). Si no, ¿por qué la interfaz no se hereda de TextBox?

+1

Ver http://msdn.microsoft.com/en-us/library/ms173153(v=vs.80).aspx para saber cuándo usar override y nuevas palabras clave. – nickvane

Respuesta

1

RichTextBox no tendría que especificar explícitamente IUndoable. Una herramienta como ReSharper probablemente incluso te lo diga y ofrezca la eliminación.

Y AFAIK no hay restricción en la herencia, solo herencia "predeterminada".

Si no desea que las personas provengan de su clase, hágalo sealed.

6

En C#, para las clases, solo existe el equivalente de la herencia pública en C++.

Puede, sin embargo, implementar una interfaz explícita o implícitamente . Cuadro de texto implementa IUdoable explícitamente, es por eso que tiene

void IUndoable.Undo() 

en lugar de simplemente

void Undo() 

en su clase TextBox.Cuando una interfaz se implementa de forma explícita, se puede acceder a los métodos de la interfaz en el objeto sólo a través de una conversión explícita:

TextBox tb = new TextBox(); 
tb.Undo(); // error 
((IUndoable)tb).Undo(); // ok 

interfaces son, como usted dice, "heredado a lo largo", pero RichTextBox re-implementos IUndoable implícita, por lo que no es necesario el reparto acceder a los métodos de la interfaz:

RichTextBox rtb = new RichTextBox(); 
rtb.Undo(); // ok 
0

en realidad RichTextBox está introduciendo un nuevo comportamiento para el método de deshacer en lugar de que sea redefinido (nueva palabra clave muestra esto) tanto si se accede RichTextBox utilizando su interfaz por defecto este método se ejecutará pero si se accede usando su interfaz padre Deshacer el método de TextBox será ejecutado .RichTextBox implementa IUndoable explícitamente así que si alguien quiere alcanzar esta clase usando la interfaz IUndoable el nuevo método será ejecutado. En resumen:

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 

Esto no es un buen enfoque porque desde Deshacer no se ha definido como virtual en la clase padre que significa que no está destinado a ser overrided y estamos rompiendo la jerarquía de herencia mediante la introducción de este nuevo método .

0

Sí Podría ser, su también conseguir compilado

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

Usted es correcta. No es necesario que RichtTextBox implemente IUndoable también. Puede ver que el compilador no está enteramente contento también, ya que el método Undo en el RichTextBox oculta el método Undo del TextBox (consulte la palabra clave new).

La única razón por la que una subclase también debe implementar la interfaz de su clase base es cuando esas clases son ComVisible y también desea exponer esa interfaz a COM.

2

Al ejecutar un ejemplo rápido se muestra la diferencia.

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

ejecute el siguiente:

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

Éstos son los resultados:


Desde el cuadro de texto:
TextBox.Undo
Desde el RichTextBox:
TextBox.Undo
De la FilthyRichTextBox:
FilthyRichTextBox.Undo