Pregunta

Tengo un objeto en un entorno multiproceso que mantiene una colección de información, por ejemplo:

public IList<string> Data 
{
    get 
    {
        return data;
    }
}

actualmente tengo return data; envuelto por un ReaderWriterLockSlim para proteger la colección de infracciones de uso compartido.Sin embargo, para estar doblemente seguro, me gustaría devolver la colección como de solo lectura, de modo que el código de llamada no pueda realizar cambios en la colección, solo ver lo que ya está allí.¿Es esto posible?

¿Fue útil?

Solución

Si su única intención es obtener el código de llamada para no cometer un error y modificar la colección cuando solo debería leer, todo lo que necesita es devolver una interfaz que no admita Agregar, Quitar, etc.¿Por qué no regresar? IEnumerable<string>?El código de llamada tendría que emitirse, lo que es poco probable que hagan sin conocer los aspectos internos de la propiedad a la que acceden.

Sin embargo, si su intención es evitar que el código de llamada observe actualizaciones de otros subprocesos, tendrá que recurrir a las soluciones ya mencionadas para realizar una copia profunda o superficial según sus necesidades.

Otros consejos

Si sus datos subyacentes se almacenan como una lista, puede usar Lista(T).AsReadOnly método.
Si sus datos se pueden enumerar, puede utilizar Enumerable.ToList método para enviar su colección a List y llamar a AsReadOnly en ella.

Voté a favor de su respuesta aceptada y estoy de acuerdo con ella. Sin embargo, ¿puedo darle algo que considerar?

No devuelvas una colección directamente.Cree una clase de lógica empresarial con un nombre preciso que refleje el propósito de la colección.

La principal ventaja de esto es el hecho de que no puede agregar código a las colecciones, por lo que siempre que tenga una "colección" nativa en su modelo de objetos, SIEMPRE tendrá código de soporte que no sea OO distribuido por todo su proyecto para acceder a ella.

Por ejemplo, si su colección fueran facturas, probablemente tendría 3 o 4 lugares en su código donde iteraría sobre facturas impagas.Podría tener un método getUnpaidInvoices.Sin embargo, el verdadero poder surge cuando empiezas a pensar en métodos como "payUnpaidInvoices(pagador, cuenta);".

Cuando pasas colecciones en lugar de escribir un modelo de objetos, nunca se te ocurrirán clases enteras de refactorizaciones.

Tenga en cuenta también que esto hace que su problema sea particularmente agradable.Si no desea que la gente cambie las colecciones, su contenedor no necesita contener mutadores.Si luego decides que en un solo caso TIENES que modificarlo, puedes crear un mecanismo seguro para hacerlo.

¿Cómo se resuelve ese problema cuando se pasa una colección nativa?

Además, las colecciones nativas no se pueden mejorar con datos adicionales.Lo reconocerá la próxima vez que pase (Colección, Extra) a más de uno o dos métodos.Indica que "Extra" pertenece al objeto que contiene su colección.

Creo que estás confundiendo conceptos aquí.

El ReadOnlyCollection proporciona un contenedor de solo lectura para una colección existente, lo que le permite (Clase A) pasar una referencia a la colección con la seguridad de saber que la persona que llama (Clase B) no puede modificar la colección (es decir,no puedo agregar o eliminar cualquier elemento de la colección.)

No hay absolutamente ninguna garantía de seguridad de subprocesos.

  • Si usted (Clase A) continúa modificando la colección subyacente después de entregarla como ReadOnlyCollection entonces la clase B verá estos cambios, se invalidarán los iteradores, etc.y, en general, estar abierto a cualquiera de los problemas habituales de concurrencia con las colecciones.
  • Además, si los elementos dentro de la colección son mutables, tanto usted (Clase A) y la persona que llama (Clase B) podrá cambiar cualquier estado mutable de los objetos dentro de la colección.

Su implementación depende de sus necesidades:- Si no te importa que la persona que llama (Clase B) vea más cambios en la colección, entonces puedes simplemente clonar la colección, repartirla y dejar de preocuparte.- Si definitivamente necesita que la persona que llama (Clase B) vea los cambios que se realizan en la colección y desea que esto sea seguro para subprocesos, entonces tiene más problemas en sus manos.Una posibilidad es implementar su propia variante segura para subprocesos de ReadOnlyCollection para permitir el acceso bloqueado, aunque esto no será trivial y no tendrá rendimiento si desea admitir IEnumerable, y aún no lo protegerá contra elementos mutables en la colección.

Hay que tener en cuenta que akuLa respuesta de solo protegerá la lista como de solo lectura.Los elementos de la lista todavía se pueden escribir mucho.No sé si hay alguna forma de proteger elementos no atómicos sin clonarlos antes de colocarlos en la lista de solo lectura.

Quieres usar el producir palabra clave.Recorres la lista IEnumerable y devuelves los resultados con rendimiento.Esto permite al consumidor utilizar el para cada uno sin modificar la colección.

Se vería algo como esto:

List<string> _Data;
public IEnumerable<string> Data
{
  get
  {
    foreach(string item in _Data)
    {
      return yield item;
    }
  }
}

Puedes utilizar una copia de la colección en su lugar.

public IList<string> Data {
get {
    return new List<T>(data);
}}

De esa manera no importa si se actualiza.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top