safe - dictionary concurrent c#
Volver a la colección como de solo lectura (7)
Tengo un objeto en un entorno de subprocesos múltiples 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 recopilación de violaciones de uso compartido. Sin embargo, para estar doblemente seguro, me gustaría devolver la colección como de solo lectura, para que el código de llamada no pueda realizar cambios en la colección, solo ver lo que ya está allí. ¿Es esto posible?
Si su única intención es obtener un código de llamada para no cometer un error, y modificar la colección cuando solo debería leer todo lo que es necesario es devolver una interfaz que no admita agregar, eliminar, etc. ¿Por qué no devolver IEnumerable<string>
? El código de llamada debería emitirse, lo que es poco probable que hagan sin conocer las partes internas de la propiedad a la que están accediendo.
Sin embargo, si su intención es evitar que el código de llamada observe actualizaciones de otros hilos, deberá recurrir a las soluciones ya mencionadas para realizar una copia profunda o superficial, según sus necesidades.
Si sus datos subyacentes se almacenan como una lista, puede usar el método List (T) .AsReadOnly .
Si sus datos pueden ser enumerados, puede usar el método Enumerable.ToList para convertir su colección a List y llamar a AsReadOnly en ella.
Creo que estás confundiendo conceptos aquí.
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 segura en el conocimiento de que la persona que llama (Clase B) no puede modificar la colección (es decir, no puede agregar o eliminar ningún elemento de la colección)
No hay absolutamente ninguna garantía de seguridad de hilos.
- Si usted (Clase A) continúa modificando la colección subyacente después de que la distribuye como
ReadOnlyCollection
, la clase B verá estos cambios, tendrá invalidados los iteradores, etc. y, en general, estará abierto a cualquiera de los problemas habituales de concurrencia con colecciones. - Además, si los elementos dentro de la colección son mutables, tanto usted (Clase A) como la persona que llama (Clase B) podrán cambiar cualquier estado mutable de los objetos dentro de la colección.
Su implementación depende de sus necesidades: - Si no le importa que la persona que llama (Clase B) vea más cambios en la colección, entonces puede simplemente clonar la colección, distribuirla y dejar de preocuparse. - Si definitivamente necesita la persona que llama (Clase B) para ver los cambios que se realizan en la colección, y desea que esto sea seguro para los subprocesos, entonces tiene más problemas en sus manos. Una posibilidad es implementar su propia variante segura de subprocesos de ReadOnlyCollection para permitir el acceso bloqueado, aunque esto no será trivial y no funcionará si desea admitir IEnumerable, y aún así no lo protegerá contra los elementos mutables en el colección.
Desea usar la palabra clave yield . Usted recorre la lista IEnumerable y devuelve los resultados con yeild. Esto permite que el consumidor use 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;
}
}
}
Puede usar una copia de la colección en su lugar.
public IList<string> Data {
get {
return new List<T>(data);
}}
De esa forma, no importa si se actualiza.
Voté por su respuesta aceptada y acepté; sin embargo, ¿podría darle algo para considerar?
No devuelva una colección directamente. Haga una clase lógica de negocios con un nombre preciso que refleje el propósito de la colección.
La principal ventaja de esto viene del hecho de que no puede agregar código a las colecciones, por lo tanto, siempre que tenga una "colección" nativa en su modelo de objetos, SIEMPRE tendrá un código de soporte no OO distribuido en todo su proyecto para acceder a él.
Por ejemplo, si su colección era facturas, probablemente tendría 3 o 4 lugares en su código donde iteraba sobre las facturas impagas. Podría tener un método getUnpaidInvoices. Sin embargo, el poder real aparece cuando comienzas a pensar en métodos como "payUnpaidInvoices (pagador, cuenta);".
Cuando pase las colecciones en lugar de escribir un modelo de objetos, nunca se le ocurrirán clases completas de refactorizaciones.
Tenga en cuenta también que esto hace que su problema sea particularmente agradable. Si no quiere que las personas cambien las colecciones, su contenedor no debe contener mutantes. Si luego decide que en un solo caso TIENE que modificarlo, puede crear un mecanismo seguro para hacerlo.
¿Cómo resuelves ese problema cuando pasas por una colección nativa?
Además, las colecciones nativas no se pueden mejorar con datos adicionales. Lo reconocerá la próxima vez que descubra que pasa (Colección, Extra) a más de uno o dos métodos. Indica que "Extra" pertenece con el objeto que contiene tu colección.
Se debe tener en cuenta que la respuesta de aku solo protegerá la lista como de solo lectura. Los elementos en la lista todavía son muy escribibles. No sé si hay alguna forma de proteger elementos no atómicos sin clonarlos antes de colocarlos en la lista de solo lectura.