I have an InfoPath form which I need to conditionally disable it's OnChange events. Since it's not possible to bind the event handlers after the form has loaded, I'm forced to rely on a global counter which indicates whether an OnChange event should be executed.
Inside each OnChange event, I check whether SuppressEventsCount == 0 before performing any actions.
To suppress events during the execution of some function or another, I simply set SuppressEventsCount++, and -- again when the function exits. The biggest problem with doing this is that it's not exception safe. So I had the bright idea to wrap the SuppressEvents counter in a class which implements iDisposable
using(SuppressEvents s = new SuppressEvents()){
// OnChange events fired here are ignored
} // OnChange events enabled again
This is working, but it's still not as ideal as a c++ solution which doesn't require the use of the "using" directive at all.
Is there some way to either:
- Trigger a destructor or some function the moment an object goes out of scope, OR
- Prevent the SuppressEvents object from being initialised outside of a "using" directive entirely
In relation to question 2, it might be possible to get around it by providing a different interface to consumers of the code. Instead of providing a public class that implements IDisposable
, and hoping they wrap it in a using
, you could provide a static method that takes a function to execute in a "suppressed" context:
public static class EventSuppressor {
public void Suppress(Action action) {
using (var s = new SuppressActions()) {
action();
}
}
private class SuppressActions : IDisposable {
...
}
}
Then consumers can use this as follows:
EventSuppressor.Suppress(() => {
// OnChange events fired here are ignored
}) // OnChange events enabled again
Of course, you have to work out whether this design is appropriate, as this will result in extra function calls, compiler generated classes and closures etc.
No and no. using
is the closest you can get to RAII (more accurately, we are talking about the resource release that follows a RAII-idiom object being destructed).
To answer your points more directly:
IDisposable
(and by extension using
) was created exactly because there is no way to do that in .NET.
using
is syntactic sugar that gets compiled as try
/finally
and only requires that the object is IDisposable
, so you cannot distinguish between usage inside a using
statement and out of it.
To answer your two questions:
- No, there is not, Garbage Collection in .NET is not deterministic in nature
- No, you can not, the
using
clause gets translated into a try/finally block type of code, and in any case you cannot detect that it is constructed from any of those two constructs, compared to outside
If you can move from C# to C++.NET (still 100% .NET if compiled with clr:safe), then you can use msclr::auto_handle which acts just like a smart pointer such as auto_ptr etc...
What it really does behind the scene in IL is a bunch of try/fault commands but this is all completely invisible to the developer and user. The whole process is simply better IMO.