2011-01-20 11 views
47

¿Cómo puedo exponer un List<T> para que sea de solo lectura, pero se puede establecer de forma privada?Lista <T> solo con un conjunto privado

Esto no funciona:

public List<string> myList {readonly get; private set; } 

Incluso si lo hace:

public List<string> myList {get; private set; } 

todavía se puede hacer esto:

myList.Add("TEST"); //This should not be allowed 

Creo que se puede tener:

public List<string> myList {get{ return otherList;}} 
private List<string> otherList {get;set;} 

Respuesta

87

Creo que está mezclando conceptos.

public List<string> myList {get; private set;} 

es ya "sólo lectura". Es decir, fuera de esta clase, nada se puede ajustar myList a una instancia diferente de List<string>

Sin embargo, si desea una lista de sólo lectura como en "No quiero que la gente sea capaz de modificar la lista de contenidos ", entonces necesitas exponer un ReadOnlyCollection<string>. Puede hacerlo a través de:

private List<string> actualList = new List<string>(); 
public ReadOnlyCollection<string> myList 
{ 
    get{ return actualList.AsReadOnly();} 
} 

Tenga en cuenta que en el primer fragmento de código, otros pueden manipular la lista, pero no pueden cambiar lo lista que tiene. En el segundo fragmento, otros obtendrán una lista de solo lectura que no pueden modificar.

+2

gran punto. Mucha gente extraña el concepto de tipos de referencia y establece la referencia como de solo lectura. 1 –

+4

Aún mejor sería que el ReadOnlyCollection como IList . – Joe

+0

+1. Devolver un System.Collections.ObjectModel.ReadOnlyCollection público es mejor que usar un "conjunto privado" en una propiedad pública porque le da una verificación en tiempo de compilación. Lo que significa que arrojará errores de compilación al usar Add() o RemoveAt() en su colección de solo lectura, mientras que el "conjunto privado" no lo hará. – MikeTeeVee

11

Si desea uso de la colección de sólo lectura ReadOnlyCollection<T>, no List<T>:

public ReadOnlyCollection<string> MyList { get; private set; } 
4

Hay una colección llamada ReadOnlyCollection<T> - es eso lo que está buscando?

4

Puede usar el método AsReadOnly() de List para devolver un contenedor de solo lectura.

1

¿Por qué está utilizando una lista. Suena como lo que realmente quiere exponer es IEnumerable

public IEnumerable<string> myList { get; private set; } 

Ahora los usuarios de la clase puede leer los artículos, pero no chagnge la lista.

+1

defectuoso!puedes convertirlo en List <> y agregar valores: MyClass m = new MyClass(); Lista x = m.Valores como lista ; x.Add ("prueba"); foreach (cadena s en m.Valores) { Console.WriteLine (s); } –

+4

Sí, puedes ** hacer ** un montón de cosas. Por supuesto, siempre puede configurar myList a algo que no sea una lista en cuyo caso ese código se romperá. Por lo general, no me preocupo por los problemas causados ​​por personas que ignoran a propósito la encapsulación. – tster

+1

no debería preocuparse de que las personas "ignoren la encapsulación". La encapsulación es encapsular y poder convertir un tipo en otro no tiene nada que ver con la encapsulación. Si vas a hacerlo, hazlo bien. –

1

También puede crear su lista de lo normal, pero mostrarse a través de una propiedad de tipo IEnumerable

private List<int> _list = new List<int>(); 

public IEnumerable<int> publicCollection{ 
    get { return _list; } 
} 
+0

defectuoso! puedes convertirlo en List <> y agregar valores: MyClass m = new MyClass(); Lista x = m.Valores como lista ; x.Add ("prueba"); foreach (cadena s en m.Values) {Console.WriteLine (s); } –

+1

De hecho, incluso _list.AsEnumerable() sería convertible a List, para mi sorpresa. –

+0

Cualquiera que tenga una dependencia de poder lanzar un 'IEnumerable ' a una' List 'sería tonto. –

4
private List<string> my_list; 

public ReadOnlyCollection<string> myList 
{ 
    get { return my_list.AsReadOnly(); } 
    private set { my_list = value; } 
} 
10

devolver un ReadOnlyCollection, que implementa IList <>

private List<string> myList; 

public IList<string> MyList 
{ 
    get{return myList.AsReadOnly();} 
} 
3
private List<string> _items = new List<string>();   

    public ReadOnlyCollection<string> Items 

    { 

     get { return _items.AsReadOnly(); } 

     private set { _items = value } 

    } 
2
private List<string> myList; 

public string this[int i] 
{ 
    get { return myList[i]; } 
    set { myList[i] = value; } 
} 
11

yo prefiero usar IEnumerabl e

private readonly List<string> _list = new List<string>(); 

public IEnumerable<string> Values // Adding is not allowed - only iteration 
{ 
    get { return _list; } 
} 
+10

Este es un buen enfoque, excepto que es defectuoso: MyClass m = new MyClass(); Lista x = m.Valores como lista ; x.Add ("prueba"); foreach (cadena s en m.Values) {Console.WriteLine (s); } // Esto me permite agregarle valores solo por conversión. –

+5

Bueno, eso es un hack :) También puedes usar el reflejo para agregar elementos a la colección interna. IEnumerable oculta la implementación de los clientes MyClass. ¿Estarás seguro de que no estoy utilizando LinkedIn? –

+3

Siempre puede reflexionar para encontrar el tipo de colección, así que siempre estaré seguro. Si vas a hacerlo, hazlo bien. Seguro que cualquiera puede usar el reflejo para "piratear" el objeto para agregar elementos, pero no hay mucho que pueda hacer al respecto. Practicar las técnicas adecuadas y usar el marco de forma adecuada es todo lo que puedes hacer. –

3

Aquí es una manera

public class MyClass 
    { 
     private List<string> _myList; 
     public ReadOnlyCollection<string> PublicReadOnlyList { get { return _myList.AsReadOnly(); } } 

     public MyClass() 
     { 
      _myList = new List<string>(); 
      _myList.Add("tesT"); 
      _myList.Add("tesT1"); 
      _myList.Add("tesT2"); 

      //(_myList.AsReadOnly() as List<string>).Add("test 5"); 
     } 

    } 
+1

Mmm ... Creo que puedes usar PublicReadOnlyList con getter new ReadOnlyCollection (_myList) –

0

Un poco tarde, pero sin embargo: No me gusta usar la envoltura ReadOnlyCollection porque todavía expone todos los métodos para modificar la colección, todos los cuales tiro a NotSupportedException cuando se accede en tiempo de ejecución. En otras palabras, implementa la interfaz IList, pero luego viola este mismo contrato en tiempo de ejecución.

Expresar que estoy realmente exponiendo una lista inmutable, por lo general recurrir a una interfaz personalizada IIndexable, que añade Longitud y un indexador a un IEnumerable (descrito en this CodeProject article). Es un contenedor como debería haberse hecho en primer lugar en mi humilde opinión.

-1

No vi esta opción sin embargo, mencionó:

private List<string> myList; 

public List<string> MyList 
{ 
    get { return myList.AsReadOnly().ToList(); } 
} 

Esto debería permitirle a exponer una lista de sólo lectura.

+0

Esto no es bueno. Primero, está creando un 'ReadOnlyCollection ' para envolver la lista. Esto no es óptimo porque una instancia de 'ReadOnlyCollection ' implementa la interfaz mutable 'IList ' y se lanza en tiempo de ejecución si se modifica. Sin embargo, luego descarta esa colección después de copiar todo su contenido en una nueva 'Lista ', que permitirá la modificación, aunque no de la lista original. Además, este código es engañoso porque expone un miembro mutable que está destinado a ser inmutable, pero en realidad es una copia accidentalmente mutable. –

3

En el marco .NET 4.5 puede exponer sólo la interfaz IReadOnlyList. Algo así como:

private List<string> _mylist; 
public IReadOnlyList<string> myList { get {return _myList;} } 

o si desea evitar que la fundición no deseada a IList

private List<string> _mylist; 
public IReadOnlyList<string> myList { get {return new List<string>(_myList);} } 
Cuestiones relacionadas