Приведение SynchronizedCollection только для чтения SynchronizedReadOnlyCollection

#c# #multithreading #list #collections #concurrency

#c# #многопоточность #Список #Коллекции #параллелизм

Вопрос:

У меня был List<T> , использовал AsReadOnly() метод и сохранил результат ReadOnlyCollection<T> . Теперь я работаю в потоках, и мне нужно сделать то же самое, но SynchronizedCollection<T> вместо List<T> и SynchronizedReadOnlyCollection<T> вместо ReadOnlyCollection<T>

Как это сделать?

Ответ №1:

Поскольку SynchronizedCollection<T> : IEnumerable<T> вы могли бы инициализировать новый экземпляр на SynchronizedReadOnlyCollection<T> основе вашего существующего SynchronizedCollection<T> , используя конструктор

 var readOnlyCollection = new SynchronizedReadOnlyCollection(synchronizedCollection.SyncRoot,
                                                            syncronizedCollection);
 

Я также думаю о другом подходе. Разница в том, что при первом подходе у вас действительно есть снимок SynchronizedCollection<T> , но при этом у вас есть только оболочка, доступная только для чтения (если вы добавите что-то в исходную коллекцию, это также обновит коллекцию, доступную только для чтения)

 public static class SynchronizedCollectionExtension
{
    public static IReadOnlyCollection<T> AsReadOnly<T>(this SynchronizedCollection<T> value)
    {
        lock (value.SyncRoot)
        {
            // this call is not expensive as it is just a thin wrapper around the IList<T>
            return new ReadOnlyCollection<T>(value);
        }
    }
}

IReadOnlyCollection<int> readOnlyCollection = collection.AsReadOnly();
 

Комментарии:

1. Спасибо за ответ! Могу ли я сделать это без создания нового объекта? Если у меня есть свойство для доступа к коллекции только для чтения, это довольно дорого.

Ответ №2:

Если у вас есть данные в перечислимом типе, просто передайте их в синхронизированные конструкторы классов:

 List<T> data = new List<T>();

var syncRoot = new object();
var syncCollection = new SynchronizedCollection<T>(syncRoot, data);

var synchronizedReadOnlyCollection = new SynchronizedReadOnlyCollection<T>(syncRoot, data);
 

Комментарии:

1. Спасибо за ответ! Могу ли я сделать это без создания нового объекта? Если у меня есть свойство для доступа к коллекции только для чтения, это довольно дорого.

2. Просто сохраните коллекцию синхронизации как переменную-член.

3. Я имею в виду это new SynchronizedReadOnlyCollection<T>(syncRoot, data);