Внедрение 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" вообще.
есть ли способ либо:
- запуск деструктора или какой-либо функции в момент выхода объекта из области видимости, Или
- предотвратите инициализацию объекта 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-идиомы, который разрушается).
чтобы ответить на ваши вопросы более прямо:
-
IDisposable
(иusing
) был создан именно потому, что нет способа сделать это .Сеть. -
using
- это синтаксический сахар, который компилируется какtry
/finally
и только требует, чтобы объектIDisposable
, так вы не можете различать использование внутриusing
заявление и из него.
чтобы ответить на ваши два вопроса:
- Нет, Нет, сбор мусора в .NET не является детерминированным по своей природе
- нет, вы не можете,
using
предложение переводится в тип кода try / finally block, И в любом случае вы не можете обнаружить, что оно построено из любой из этих двух конструкций, по сравнению с outside
Если вы можете перейти с C# на C++.NET (все еще 100% .NET при компиляции с clr: safe), то вы можете использовать msclr::auto_handle, который действует так же, как умный указатель, такой как auto_ptr и т. д...
то, что он действительно делает за сценой в IL, - это куча команд try/fault, но все это совершенно невидимо для разработчика и пользователя. Весь процесс просто лучше ИМО.