2010-12-15 6 views
5

Estoy tratando de escribir una clase base abstracta para las colecciones de solo lectura que implementan IList. Dicha clase base debe implementar el conjunto de indicadores para lanzar un NotSupportedException, pero deje el indizador get como abstracto. ¿C# permite tal situación? Esto es lo que tengo hasta ahora:Extractor abstracto con fraguado de hormigón en C#

public abstract class ReadOnlyList : IList { 

    public bool IsReadOnly { get { return true; } } 

    public object this[int index] { 
     get { 
      // there is nothing to put here! Ideally it would be left abstract. 
      throw new NotImplementedException(); 
     } 
     set { 
      throw new NotSupportedException("The collection is read-only."); 
     } 
    } 

    // other members of IList ... 
} 

Idealmente ReadOnlyList sería capaz de poner en práctica la incubadora pero deje el captador abstracta. ¿Hay alguna sintaxis que permita esto?

+5

En caso de que esto no es sólo un ejercicio, usted tiene ReadOnlyCollection en el marco –

+0

Gracias; Usualmente uso ReadOnlyCollection , aunque este caso específico requería una implementación personalizada de IList . Tiendo a simplificar mis escenarios al mínimo necesario para hacer una pregunta. –

Respuesta

8

delegar el trabajo a los miembros protegidos que luego se puede marcar como abstracta o virtual dependiendo del comportamiento deseado. Intentar algo como esto:

// implementor MUST override 
protected abstract object IndexerGet(int index); 

// implementor can override if he wants.. 
protected virtual void IndexerSet(int index, object value) 
{ 
    throw new NotSupportedException("The collection is read-only."); 
} 

public object this[int index] { 
    get { 
    return IndexerGet(index); 
    } 
    set { 
    IndexerSet(index, value); 
    } 
} 
+0

IndexerSet debería * probablemente * no ser virtual, de hecho, solo lanzar 'NotSupportedException' en el mismo setter está bien. –

+1

Gracias m0sa. He aceptado esto como la respuesta, ya que es la única respuesta para lograr el objetivo de implementar el setter y forzar a las clases derivadas a implementar el getter. ¡Sin mencionar que es prácticamente la única respuesta que compilaría! –

-1

¿Por qué le gustaría tener setter en absoluto? La ausencia de setter indicaría su propiedad de solo lectura.

EDIT: jgauffin señaló que setter viene de IList. Entonces puede tener dos opciones:

  1. Implemente IList en privado y proporcione getter abstracto público para indexador (no 100% seguro si puedo tener dos indexadores).
  2. Indexer getter invocaría un método abstracto como GetItem.
+0

Porque 'IList' define el indexador. – jgauffin

+0

Es [requerido] (http://msdn.microsoft.com/en-us/library/system.collections.ilist.item.aspx) por la interfaz. –

0

¿Por qué no hace que el colocador sea privado?

public abstract class ReadOnlyList : IList 
    { 

     public bool IsReadOnly { get { return true; } } 

     public object this[int index] 
     { 
      get 
      { 
       // there is nothing to put here! Ideally it would be left abstract. 
       throw new NotImplementedException(); 
      } 
      private set 
      { 
       // your private implementation 
      } 
     } 

     // other members of IList ... 
    } 
+4

Error de compilación ya que el indexador se define en 'IList' – jgauffin

+2

La interfaz lo requiere para que sea público, y usted no abordó el deseo de mantener el getter abstracto. –

+1

mm derecha, no pensé en eso –

2

No, no puede tener una propiedad con un miembro abstracto y la otra implementada. Lo que haría es establecer toda la propiedad como abstracta y redefinirla en los herederos para hacer lo que quiera.

+0

Gracias SoMoS; aunque acepté la respuesta de m0sa como la que respondió la pregunta, en última instancia, me he ido con el enfoque que sugirió, para evitar un nivel adicional de indirección. –

+0

No hay problema, de todos modos, la respuesta de mOsa también es buena. –

0

No. Y realmente rompe el Principio de Sustitución de Liskov si encuentras una manera de hacerlo.

Leer más sobre LSP aquí: Can you explain Liskov Substitution Principle with a good C# example?

+0

¿Cómo rompe esto LSP?La subclase concreta debería proporcionar una implementación getter concreta. Si lo hace, esa subclase debería (en ausencia de otros problemas) ser un 'IList' de buen comportamiento (que están [permitidos] (http://msdn.microsoft.com/en-us/library/system.collections.ilist. isreadonly.aspx) para que sea de solo lectura. –

+1

Porque cualquiera que use un 'IList' esperará poder obtener y establecer elementos en la lista. 'ReadOnlyCollection' en .Net framework también viola LSP ya que no cumple con ese requisito. – jgauffin

+0

No. Si revisaste mi enlace, verías que 'IList' estaba explícitamente diseñado para ser potencialmente de solo lectura; por eso hay una propiedad 'IList.IsReadOnly'. Por lo tanto, una subclase de solo lectura puede "sustituir" fácilmente. –

0

Si usted quiere que sea una colección de sólo lectura entonces ¿por qué aplicar IList?

En su lugar, debe implementar IEnumerable.

+1

IList está explícitamente [permitido] (http: // msdn .microsoft.com/en-us/library/system.collections.ilist.isreadonly.aspx) para que sea de solo lectura. 'IEnumerable' no proporciona acceso aleatorio. –

+0

Aunque esto no es tan completo como la solución 'ReadOnlyCollection <>', en la práctica suele ser suficiente y tiene la virtud de ser una API aún más simple, y eso es lo que cuenta, ¿verdad? Solo recomendaría ReadOnlyCollection donde IEnumerable es insuficiente. –

+0

Además, los jugadores de 'IEnumerable' son más agradables con el sistema de tipos: comúnmente uso métodos para barajar y clasificar colecciones, y estas funcionan en ILists. Los ILists de solo lectura fallarán en el tiempo de ejecución, mientras que pasar un IEnumerable fallará en el momento de la compilación; ese es un comportamiento más agradable. –

-2

usted no necesita un regulador

public abstract object this[int index] { get; } 
+0

Lee las otras respuestas que dicen lo mismo. –

Cuestiones relacionadas