2010-08-25 8 views
11

Entiendo que una clase que hereda de otra clase puede ocultar una propiedad utilizando la palabra clave new. Sin embargo, esto oculta una implementación específica de la propiedad, por lo que puedo ver cómo se podría usar.¿Alguna vez hay una razón para ocultar miembros heredados en una interfaz?

¿Hay alguna razón práctica para ocultar miembros en interfaces que implementan otras interfaces? Por ejemplo, considere el ejemplo a continuación. IChildInterface implementa IParentInterface, y oculta PropertyA.

interface IParentInterface 
{ 
    string Name { get; set; } 
    int PropertyA { get; set; } 
    int PropertyB { get; set; } 
} 

interface IChildInterface : IParentInterface 
{ 
    int PropertyA { get; set; } 
    int PropertyC { get; set; } 
} 

Respuesta

20

¿Hay alguna razón práctica para ocultar miembros en las interfaces que implementan otras interfaces?

Sure. El hecho de que el BCL en sí mismo utiliza este patrón es indicativo de que el patrón es práctico.Por ejemplo:

interface IEnumerable 
{ 
    IEnumerator GetEnumerator(); 
} 
interface IEnumerable<T> : IEnumerable 
{ 
    new IEnumerator<T> GetEnumerator(); 
} 

Los diseñadores de IEnumerable<T> deseaban ser compatible hacia atrás con IEnumerable sino también querían asegurarse de que cada uso de GetEnumerator en la interfaz genérica llamada la versión genérica. Ocultar es el mecanismo apropiado en este caso.

Por alguna discusión adicional sobre los puntos sutiles acerca de cómo ocultar método, consulte:

http://blogs.msdn.com/b/ericlippert/archive/2008/05/21/method-hiding-apologia.aspx

1

Ocultar los miembros heredados nunca debe hacerse deliberadamente como parte de un diseño. El lenguaje permite la ocultación de métodos para evitar cambios en el ancestro (en las versiones principales de una biblioteca) de los descendientes rotos que ya tienen un miembro con el mismo nombre definido.

Dicho esto, a veces es conveniente ocultar un método heredado con un método equivalente que devuelve un tipo más específico. En estos casos, lo único que está haciendo es encasillar el azúcar: tenga cuidado de no cambiar la semántica del método porque las personas que llaman pueden llamar fácilmente al método ancestro en lugar del suyo.

Consulte también: Is there ever a situation where derived class should hide …?

+0

Estoy de acuerdo cuando se trata de clases (incluso en la excepción que das) pero creo que es diferente cuando se trata de interfaces. –

0

supongo que si se va a aplicar de forma explícita IChildInterface podría haber un caso en el que te gustaría ocultó propertyâ

+0

Pero desde IChildInterface implementa IParentInterface habría ninguna implementions de IChildInterface (implícita o explícita) también aplicar IParentInterface? –

+0

Sí, creo que ahora que lo pienso, probablemente tengas razón. – taylonr

2

Las interfaces no pueden ocultar las interfaces de los padres (tal vez?) por completo, pero la clase implementadora puede, lo que puede ser útil.

Considere una clase MyStringList que es una lista de solo lectura que implementa IList<string>. Tendremos como un simple paso a través de la simplicidad: Algunos de los miembros son bastante inútil, por lo que podemos hacer de la siguiente manera:

//implement this one implicitly, as it's useful. 
public int Count 
{ 
    return _list.Count; 
} 
//do a half-and-half on the indexer 
public string this[int index] 
{ 
    get 
    { 
    return _list[index]; 
    } 
} 
string IList<string>.this[int index] 
{ 
    get 
    { 
    return this[index]; 
    } 
    set 
    { 
    throw new NotSupportedException("Collection is read-only."); 
    } 
} 
//hide some pointless ones. 
bool ICollection<string>.IsReadOnly 
{ 
    get 
    { 
    return true; 
    } 
} 
void IList<string>.Insert(int index, string item) 
{ 
    throw new NotSupportedException("Collection is read-only."); 
} 
void IList<string>.RemoveAt(int index) 
{ 
    throw new NotSupportedException("Collection is read-only."); 
} 
void ICollection<string>.Add(string item) 
{ 
    throw new NotSupportedException("Collection is read-only."); 
} 
void ICollection<string>.Clear() 
{ 
    throw new NotSupportedException("Collection is read-only."); 
} 
bool ICollection<string>.Remove(string item) 
{ 
    throw new NotSupportedException("Collection is read-only."); 
} 

Alguien trata de la interfaz a través MyStringListIList<string> tiene que ser capaz de llamar estos miembros inútiles, pero no es necesario que alguien que se ocupe del MyStringList lo haga.

Ahora, con esto posible para la clase, una interfaz puede forzar tal implicación en la clase haciendo coincidir el nombre de una interfaz principal. El ejemplo de clase es IEnumberable<T> donde el GetEnumerator() coincide con el de IEnumerable del que hereda. Por lo tanto, la clase puede implementar implícitamente solo uno, y debe ocultar el otro o ambos (ya que uno siempre puede convertir el resultado (un IEnumerator<T>) en el tipo de resultado del otro (un IEnumerator), entonces el comportamiento más sensato es implementar implícitamente la versión IEnumberable<T>, y poner en práctica de manera explícita la IEnumerable uno (normalmente devolviendo el resultado de la otra).

Sin embargo, mientras que las fuerzas de escondite al menos uno que se oculta, no hay nada para obligar a que la elección particular, en cuanto a que (si Cualquiera) se implementa implícitamente, más allá de que uno tenga una ventaja tan obvia sobre la otra que pocos lo harían de otra manera.

5

Un caso he encontrado escondido miembro de base útil es cuando se tiene una interfaz base que expone un captador en una propiedad pero el Interfaz derivada quiere exponer un setter:

public interface IBase 
{ 
    int MyProperty { get; } 
} 

public interface IDerive : IBase 
{ 
    // you need to specify the getter here too 
    new int MyProperty { get; set; } 
} 
Cuestiones relacionadas