Допустимо ли использовать yield return внутри блокировки?
1,00
р.
р.
Есть два вопроса к коду, приведенному ниже: Допустимо ли использовать yield return внутри блокировки? Что произойдёт с блокировкой, когда мы будет крутить метод Get() в цикле foreach? public IEnumerable Get() { _lock.EnterReadLock() try { foreach (var item in _dictionary) { yield return new SomeObject(item.Key, item.Value) } } finally { _lock.ExitReadLock() } } private ReaderWriterLockSlim _lock = new ReaderWriterLockSlim()
Ответ Ограниченно допустимо. Когда вы такую последовательность будете обходить в цикле foreach - то перед входом в цикл блокировка будет взята, а после выхода - освобождена. Также блокировка будет освобождена при любом прерывании цикла. Однако, использование IEnumerable не ограничивается простыми циклами. При использовании блокировок всегда важно небольшое время удержания блокировки - а тут вы его растягиваете на не зависящее от вас время! Так можно легко и до взаимоблокировки доиграться. Обычно лучше всего под блокировкой получить копию данных, и работать в дальнейшем уже с ней: public IEnumerable Get() { IEnumerable> d _lock.EnterReadLock() try { d = _dictionary.ToList() } finally { _lock.ExitReadLock() } foreach (var item in d) { yield return new SomeObject(item.Key, item.Value) } } Или даже вот так: public IEnumerable Get() { _lock.EnterReadLock() try { return _dictionary.Select(item => new SomeObject(item.Key, item.Value)).ToList() } finally { _lock.ExitReadLock() } }