2009-03-06 14 views
19

tengo la clase siguiente:"sólo lectura" propiedad de acceso en C#

class SampleClass 
{ 
    private ArrayList mMyList; 

    SampleClass() 
    { 
     // Initialize mMyList 
    } 

    public ArrayList MyList 
    { 
     get { return mMyList;} 
    } 
} 

Quiero que los usuarios puedan obtener mMyList que es por lo expuesto el "recibo" a través de una propiedad sin embargo no lo hago desea cambios que hacen al objeto (es decir, MyList.Add (new Class());) para hacer su camino de regreso a mi clase.

Supongo que puedo devolver una copia del objeto, pero puede ser lenta y estoy buscando una forma que proporcione un error en tiempo de compilación informando al usuario que no deben esperar poder modificar el valor devuelto de la propiedad.

¿Esto es posible?

+0

pregunta relacionada: http://stackoverflow.com/questions/681287/how-to-make-a-reference-type-property-readonly –

+2

¿'List : ReadOnlyCollection ' en .NET 4.5 cambia algo de esto? http://www.infoq.com/news/2011/10/ReadOnly-WInRT/ –

Respuesta

25

Con un ArrayList, usted está bastante limitado porque no hay una clase de colección no genérica en el BCL. La solución rápida y sucia es devolver un tipo de IEnumerable.

public IEnumerable MyList 
    { 
     get { return mMyList;} 
    } 

Esto en realidad no evitar que alguien fundición a ArrayList pero no va a permitir que las modificaciones de forma predeterminada, ya sea

Puede devolver una lista de sólo lectura efectiva llamando ArrayList.ReadOnly. Sin embargo, su tipo de devolución es ArrayList, por lo que el usuario aún podría compilar con .Add, pero produciría un error de tiempo de ejecución.

1

Debe envolver el valor de retorno en una colección de solo lectura.

19

Utilice el método ArrayList.ReadOnly() para construir y devolver un contenedor de solo lectura alrededor de la lista. no copiará la lista, sino que simplemente hará un contenedor de solo lectura a su alrededor. Para obtener la verificación en tiempo de compilación, probablemente desee devolver el contenedor de solo lectura como IEnumerable como sugiere @Jared.

public IEnumerable MyList 
{ 
    get { return ArrayList.ReadOnly(mMyList); } 
} 

Una colección que es de sólo lectura es simplemente una colección con un envoltorio que impide la modificación de la colección . Si se realizan cambios en la colección subyacente , la colección de solo lectura refleja esos cambios.

Este método es una operación O (1).

Reference

+2

Estoy en contra de esta solución porque convierte lo que debería ser un error de tiempo de compilación en un error de tiempo de ejecución. – JaredPar

+0

-1, OP: "Estoy buscando un modo que proporcione un ** error en tiempo de compilación **" –

+0

Sin copiar a ReadOnlyCollection, que también dijo que quería evitar, elijo forzar la lectura solo por pretender ser de solo lectura. Hacer ambas cosas es probablemente mejor. – tvanfosson

-3

Simplemente haga la propiedad según lo sellado (o NotInheritable en VB.NET) y de sólo lectura, como esto:

public sealed readonly ArrayList MyList 
    { 
     get { return mMyList;} 
    } 

También no se olvide de hacer el campo de respaldo como de sólo lectura :

private readonly ArrayList mMyList; 

Pero con el fin de inicializar el valor de mMyList, debe inicializar solamente en el constructor, una s en este ejemplo:

public SampleClass() 
{ 
    // Initialize mMyList 
    mMyList = new ArrayList(); 
} 
10

Solo para expandir la respuesta de JaredPar. Como dijo, devolver el campo de respaldo real no es completamente seguro, ya que el usuario todavía puede emitir dinámicamente el IEnumerable de vuelta a un ArrayList.

escribiría algo como esto para asegurarse de que no modificaciones a la lista original se hacen:

public IEnumerable MyList 
{ 
    get 
    { 
     foreach (object o in mMyList) 
      yield return o; 
    } 
} 

Por otra parte, me gustaría probabily también utilizar una lista genérica (IEnumerable<T>) Para pertenecer completamente a salvo.

+0

* Este * es el correcto, desearía poder votar dos veces. ¿Algún problema con no llamar 'yield break 'después del ciclo? – Jay

+0

@Jay: no hay necesidad de un 'salto de rendimiento' explícito en 'después del ciclo. El final del método implica el final del 'Enumerator' (y' MoveNext' devolverá correctamente 'false'). –

+0

Con esta solución, ¿el usuario no pierde la funcionalidad de ArrayList, como el acceso aleatorio rápido y el recuento rápido? –

4

Utilice un ReadOnlyCollection.

return new ReadOnlyCollection<object>(mMyList).

También puede hacer que el campo ReadOnlyCollection y refleje automáticamente los cambios en la lista subyacente. Esta es la solución más eficiente.

Si sabe que mMyList sólo contiene un tipo de objeto (por ejemplo, no tiene nada pero DateTime), puede devolver un ReadOnlyCollection<DateTime> (o algún otro tipo) para la seguridad de tipos adicional. Si estás usando C# 3, sólo tiene que escribir

return new ReadOnlyCollection<DateTime>(mMyList.OfType<DateTime>().ToArray())

Sin embargo, esto no se actualizará automáticamente con la lista subyacente, y también es menos eficiente (Este copiará toda la lista) . La mejor opción es hacer un genérico mMyList List<T> (por ejemplo, un List<DateTime>)

0

Disponible a partir de v2.0 .NET

public ArrayList MyList { get; private set; } 
+0

Aún podría usar Agregar en una lista existente. –

Cuestiones relacionadas