Внедрение RAII в C#

У меня есть форма InfoPath, которую мне нужно условно отключить, это события OnChange. Поскольку невозможно связать обработчики событий после загрузки формы, я вынужден полагаться на глобальный счетчик, который указывает, должно ли выполняться событие OnChange. Внутри каждого события OnChange я проверяю, SuppressEventsCount == 0 Перед выполнением каких-либо действий. Чтобы подавить события во время выполнения той или иной функции, я просто устанавливаю SuppressEventsCount++ и -- снова, когда функция завершает работу. Самая большая проблема с этим заключается в том, что это не исключение. Поэтому у меня была яркая идея обернуть счетчик SuppressEvents в класс, который реализует iDisposable

using(SuppressEvents s = new SuppressEvents()){
   // OnChange events fired here are ignored
} // OnChange events enabled again

это работает, но это все еще не так идеально, как решение c++, которое не требует использования директивы "using" вообще.

есть ли способ либо:

  1. запуск деструктора или какой-либо функции в момент выхода объекта из области видимости, Или
  2. предотвратите инициализацию объекта SuppressEvents вне директивы "using" полностью

4 ответов


что касается вопроса 2, возможно, удастся обойти его, предоставив другой интерфейс потребителям кода. Вместо предоставления открытого класса, который реализует IDisposable, и надеясь, что они обернуть его в using, вы можете предоставить статический метод, который принимает функцию для выполнения в" подавленном " контексте:

public static class EventSuppressor {
    public void Suppress(Action action) {
        using (var s = new SuppressActions()) {
            action();
        }
    }

    private class SuppressActions : IDisposable {
        ...
    }
}

затем потребители могут использовать это следующим образом:

EventSuppressor.Suppress(() => {
    // OnChange events fired here are ignored
}) // OnChange events enabled again

конечно, вы должны разработать, подходит ли этот дизайн, как это приведет к дополнительным вызовам функций, сгенерированным компилятором классам и закрытиям и т. д.


нет и нет. using ближе всего вы можете добраться до RAII (точнее, мы говорим о выпуске ресурса, который следует за объектом RAII-идиомы, который разрушается).

чтобы ответить на ваши вопросы более прямо:

  1. IDisposableusing) был создан именно потому, что нет способа сделать это .Сеть.
  2. using - это синтаксический сахар, который компилируется как try/finally и только требует, чтобы объект IDisposable, так вы не можете различать использование внутри using заявление и из него.

чтобы ответить на ваши два вопроса:

  1. Нет, Нет, сбор мусора в .NET не является детерминированным по своей природе
  2. нет, вы не можете,using предложение переводится в тип кода try / finally block, И в любом случае вы не можете обнаружить, что оно построено из любой из этих двух конструкций, по сравнению с outside

Если вы можете перейти с C# на C++.NET (все еще 100% .NET при компиляции с clr: safe), то вы можете использовать msclr::auto_handle, который действует так же, как умный указатель, такой как auto_ptr и т. д...

то, что он действительно делает за сценой в IL, - это куча команд try/fault, но все это совершенно невидимо для разработчика и пользователя. Весь процесс просто лучше ИМО.