2010-02-19 13 views

Respuesta

12

Usted podría exponerlo como un IEnumerable<T>, pero no acaban de volver directamente:

public IEnumerable<object> Objects { get { return obs.Select(o => o); } } 

Desde que se indica sólo quería recorrido de la lista, esto es todo lo que necesita.

Uno podría estar tentado a devolver el List<object> directamente como un IEnumerable<T>, pero eso sería incorrecto, ya que fácilmente se podría inspeccionar el IEnumerable<T> en tiempo de ejecución, determinar que es un List<T> y echarlo a tal o mutar el contenido.

Sin embargo, al usar return obs.Select(o => o); se termina devolviendo un iterador sobre el List<object>, no una referencia directa al List<object>.

Algunos podrían pensar que esto califica como una "expresión degenerada" según la sección 7.15.2.5 de la Especificación del lenguaje C#. Sin embargo, Eric Lippert goes into detail as to why this projection isn't optimized away.

Además, la gente sugiere que uno use el AsEnumerable extension method. Esto es incorrecto, ya que se mantiene la identidad de referencia de la lista original. Desde la sección Comentarios de la documentación:

AsEnumerable<TSource>(IEnumerable<TSource>) El método no tiene otro efecto que cambiar el tipo de tiempo de compilación de la fuente de un tipo que implementa IEnumerable<T>- IEnumerable<T> sí.

En otras palabras, todo lo que hace es convertir el parámetro fuente a IEnumerable<T>, lo que no ayuda a proteger la integridad referencial, se devuelve la referencia original y se puede volver a List<T> y se puede usar para cambiar la lista.

+2

Tenga en cuenta que nunca optimizaríamos una llamada * explicit * para seleccionar si eso aparecía en su código. Optimizaremos la llamada implícita a Seleccionar al transformar una expresión de consulta en llamadas a métodos. Si dices "de x en y donde b selecciona x", no hay una llamada de selección, solo un lugar. Pero si dices "de x en y selecciona x", no generamos "y", generamos una llamada de selección para asegurar la inmutabilidad del resultado. –

0

¿Ha considerado derivar una clase de System.Collections.ReadOnlyCollectionBase?

11

Puede usar un ReadOnlyCollection o hacer una copia del List y devolverlo en su lugar (teniendo en cuenta la penalización del rendimiento de la operación de copia). También puede usar List<T>.AsReadOnly.

+0

la respuesta está incompleta. codificar por favor –

1

exponer una ReadOnlyCollection<T>

+0

cómo? respuesta pobre –

+1

No es exactamente un problema hacer que la persona que pregunta busca un poco. El primer resultado en Google hace obvio cómo exponer un 'ReadOnlyCollection '. – user7116

+0

sixlettervariables, obviamente te pierdes el punto del sitio. –

2

Usted puede hacer esto de dos maneras:

  1. ya sea por la conversión de la lista en una colección Sólo lectura:

    new System.Collections.ObjectModel.ReadOnlyCollection<object>(this.obs) 
    
  2. o devolviendo un IEnumerable de los artículos:

    this.obs.AsEnumerable() 
    
2

a su interfaz de añadir el siguiente método de firma: pública IEnumerable TraverseTheList()

implimented como tan:

public IEnumerable<object> TraverseTheList() 
{ 

    foreach(object item in obj) 
    { 
     yield return item; 
    } 


} 

que le permitirá realizar las siguientes acciones:

foreach(object item in Something.TraverseTheList()) 
{ 
// do something to the item 
} 

El retorno de rendimiento le dice al compilador que construya un enumerador para usted.

+0

un ángulo diferente; excelente. –

3

Esto ya se ha dicho, pero no veo ninguna de las respuestas como superclear.

La forma más fácil es simplemente devolver un ReadOnlyCollection

private List<object> objs; 

public ReadOnlyCollection<object> Objs { 
    get { 
     return objs.AsReadOnly(); 
    } 
} 

La desventaja de esto es que si usted quiere cambiar su puesta en práctica más adelante, a continuación, algunas personas que llaman pueden ya ser dependiente en el hecho, de que la la colección proporciona acceso aleatorio. Así que una definición más seguro sería simplemente exponer a un IEnumerable

public IEnumerable<object> Objs { 
    get { 
     return objs.AsReadOnly(); 
    } 
} 

Tenga en cuenta que usted no tiene que llamar AsReadOnly() para compilar el código. Pero si no lo hace, la persona que llama simplemente arroja el valor de retorno a una lista y modifica su lista.

// Bad caller code 
var objs = YourClass.Objs; 
var list = objs as List<object>; 
list.Add(new object); // They have just modified your list. 

Lo mismo es posible problema también existe con esta solución

public IEnumerable<object> Objs { 
    get { 
     return objs.AsEnumerable(); 
    } 
} 

Así que sin duda recomiendo que llame AsReadOnly() en su lista, y devuelve ese valor.

+0

gran combinación de simple + seguro. –

Cuestiones relacionadas