Автофлаг
Блокировка с использованием флагов используется часто, по причине тривиальной реализации и минимума используемых ресурсов. Необходимость сбрасывать флаг не только по выходу из блока но и в случае возникновения исключения вынуждает загромождать код блоками try/finally как показано ниже.
bool _uiLock; try { _uiLock = true //выполнение действий } finally { _uiLock = false; }
Реализация
Использование встроенной языковой конструкции using которая для объектов, реализующих интерфейс IDisposable, автоматически создает блок try/finally, а в блоке finally генерирует вызов метода Dispose, позволяет реализовать класс тривиальной блокировки, обеспечивающий более компактную форму записи.
using System; using System.Diagnostics; namespace IndustrialSoftware { public class Flag { private bool _flag; public Flag() {} void IDisposable.Dispose() { _flag = false; } public bool Flagged { get { return _flag; } } public Flag Flag() { if (_flag) { Debug.Assert(false); throw new InvalidOperationException(); } _flag = true; return this; } public static implicit operator bool(Flag f) { return f.Flagged; } } }
Замечания по реализации
Интерфейс IDisposable реализован явно, что бы уменьшить вероятность вызова функции Dispose вне блока using. Неявное преобразование к bool позволяет использовать класс в логических выражениях.
Пример использования
Flag _uiLockFlag; using (_uiLockFlag.Flag()) { //выполнение действий } //Неявное проверка флага выполняется так же, как и значение переменной типа bool if(_uiLockFlag) return;