2010-08-18 17 views
21

que desee hacer esto:Herencia de interfaz: ¿es posible extender las propiedades?

interface IBase 
{ 
    string Property1 { get; } 
} 

interface IInherited : IBase 
{ 
    string Property1 { get; set; } 
} 

Para que IInherited tendría el heredaron propiedad Property1 con mayor funcionalidad para permitir set.

¿Es esto posible? ¿Cuál es la sintaxis?

EDITAR: tenga en cuenta Puse la palabra "heredada" en negrita. Estoy preguntando específicamente sobre heredar la propiedad, no esconderla detrás de una nueva.

+3

Creo que aquí hay confusión entre la herencia de las clases y la herencia de las interfaces. Una interfaz realmente no hereda a otra en el mismo caso en que una clase hereda a otra. Todo lo que dice su código es que IInherited también implementa IBase. El código está bien, solo genera una advertencia de compilación porque está cambiando la firma de Property1 en la interfaz. Puedes borrar esto con nuevo. –

+0

Como lo señalaron muchos otros, esta sintaxis no es posible, pero creo que debería ser así. Si usa Reflection en Property1, habría un método Property1_get y un método Property1_set, por lo que, lógicamente, parece que debería poder implementarlos por separado. Y la falta de poder hacerlo definitivamente hace que duplique código a veces (o aguante la nueva palabra clave). – cedd

Respuesta

24

Si el hecho de que la única manera de hacer esto es mediante el uso de la palabra clave new te molesta, entonces en mi opinión que usted está pensando acerca de las interfaces equivocadas.

Claro, usted podría decir que IInherited "hereda de" IBase; pero ¿qué significa eso realmente ? Estas son interfaces; ellos establecen contratos de código. Al ocultar la propiedad IBase.Property1 con new string Property1 { get; set; }, no está ocultando ninguna funcionalidad. Por lo tanto, la razón tradicional por la que muchos desarrolladores consideran que esconderse es algo "malo", que viola el polimorfismo, es irrelevante en este caso.

Pregúntese: lo que realmente importa cuando se trata de interfaces? Proporcionan una garantía de responder a ciertas llamadas a métodos, ¿verdad?

Por lo tanto, teniendo en cuenta las dos interfaces siguientes:

interface IBase 
{ 
    string Property1 { get; } 
} 

interface IInherited : IBase 
{ 
    new string Property1 { set; } 
} 
  1. Si un objeto implementa IBase, se puede leer su propiedad Property1.
  2. Si un objeto implementa IInherited, puede leer su propiedad Property1 (al igual que con una implementación IBase), y también puede escribir en él.

Una vez más, aquí no hay nada realmente problemático.

+4

Tiene la razón, excepto en casos de implementación explícita. Puede tener implementaciones diferentes para cada versión, por lo tanto, todavía está oculto. Existe la posibilidad de que alguien que implemente su interfaz pueda hacer esto, ya sea accidentalmente o a propósito, por lo que debe tener cuidado de cómo consume estas interfaces. Si desea evitar este problema y todavía usa la herencia, utilice "nuevo", pero no agregue un segundo captador. –

+0

@Merlyn, de acuerdo. Al eliminar la segunda declaración get esto ya no violaría el LSP. –

+1

Su código declara dos * get * getters para la propiedad. En 'IInherited', probablemente quiera declarar solo' nueva cadena Property1 {set; } ' Una clase que implementa 'IInherited' puede tener una propiedad con un getter y un setter e implementará ambas interfaces. – Timwi

1

Su código debería funcionar de todos modos ... solo crea una advertencia de compilador debido a la ocultación de Property1. Para borrar esta marca de advertencia Propiedad1 en IInherited con el nuevo prefijo

0

Usted puede marcar la propiedad con la "nueva" palabra clave, o se puede omitir la herencia:

public interface IBase 
{ 
    string Property1 { get; } 
} 

public interface IInherited : IBase 
{ 
    new string Property1 { get; set; } 
} 

O:

public interface IBase 
{ 
    string Property1 { get; } 
} 

public interface IInherited 
{ 
    string Property1 { get; set; } 
} 

de cualquier manera, esto debería funcionar:

public class SomeClass : IInherited, IBase 
{ 
    public string Property1 
    { 
     get 
     { 
      // ... 
     } 
     set 
     { 
      // ... 
     } 
    } 
} 

es posible que desee pensar muy bien antes de hacer una cadena de herencia para sus interfaces, sin embargo. ¿Quién va a ver qué interfaz? ¿Tendrías que enviar contenido a IIherited al aprobar un IBase? Si es así, ¿se le puede garantizar que puede hacer ese reparto (si permite clases creadas por el usuario, entonces la respuesta es no)? Este tipo de herencia realmente puede dañar la (re) usabilidad si no tienes cuidado.

1

No explícitamente, no. Tiene dos opciones:

public interface IBase 
{ 
    string Property1 { get; } 
} 

public interface IInherited : IBase 
{ 
    void SetProperty1(string value); 
} 

O puede simplemente matar el compilador de advertencia con la palabra clave: new

public interface IBase 
{ 
    string Property1 { get; } 
} 

public interface IInherited : IBase 
{ 
    new string Property1 { get; set; } 
} 

menos que implemente IInherited.Property1 explícitamente, IBase se unirá a su aplicación ajustable automáticamente.

+0

En la implementación solo hay 1 propiedad llamada Property1. Si accede a la implementación a través de una referencia a IIherited puede llamar a getter y setter, y si accede a través de IBase, solo puede llamar al getter. Pero este es el comportamiento requerido, ¿no? –

+0

Sí, eso es lo que quiero. Pero probablemente tenga que ir con los métodos getter/setter, ya que parece que esto no se puede hacer ... – Malki

+0

Se puede hacer, exactamente como lo está haciendo ... ¿está obteniendo un error de compilación? ¿Cuál es el error? –

1

Desafortunadamente no, las propiedades no se pueden extender como tal. Sin embargo, sólo puede ocultar la propiedad utilizando nueva:

interface IInherited : IBase 
{ 
    // The new is actually unnecessary (you get warnings though), hiding is automatic 
    new string Property1 { get; set; } 
} 

O bien, puede hacer sus propios métodos get y set que puede ser anulado (estilo de Java buena 'ol):

interface IBase 
{ 
    string GetProperty1(); 
} 
interface IInherited : IBase 
{ 
    void SetProperty1(string str); 
} 

Propiedades En realidad, el compilador los convierte en métodos getter y setter.

1

Ocultar a un miembro está violando el Principio de Sustitución de Liskov y casi no se debe hacer nunca. Al ocultar este miembro, está introduciendo un error muy difícil de ubicar, ya que se producirán 2 resultados diferentes dependiendo de si el objeto se lanza como IBase1 o si se lo lanza a IBase.

http://en.wikipedia.org/wiki/Liskov_substitution_principle

+2

-1. Esto no se esconde en el sentido tradicional, ya que las interfaces no son compatibles con el polimorfismo de todos modos. –

+1

Adam: Creo que Chris está en lo correcto, IFF colocamos su comentario en el contexto de las interfaces implementadas explícitamente, con diferentes implementaciones. –

+2

Una clase que implemente IInherited podría convertirse en un IBase con menores derechos para modificarla, no se anula la implementación de un método, ya que el getter devolverá el mismo (ya que las dos interfaces 'comparten' la implementación de getter) –

Cuestiones relacionadas