Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing RAII in C#

Tags:

c#

raii

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:

  1. Trigger a destructor or some function the moment an object goes out of scope, OR
  2. Prevent the SuppressEvents object from being initialised outside of a "using" directive entirely
like image 356
Trent Avatar asked Apr 02 '12 08:04

Trent


People also ask

Does C have RAII?

> C does not have RAII-like memory management in any way. C does not have memory management in any way period. The C standard library does. How you get to something with dynamic scoping like RAII in C is to use a different library for managing memory.

What is RAII in programming?

Resource Acquisition Is Initialization or RAII, is a C++ programming technique which binds the life cycle of a resource that must be acquired before use (allocated heap memory, thread of execution, open socket, open file, locked mutex, disk space, database connection—anything that exists in limited supply) to the ...

How is RAII implemented in C++?

The key to RAII is the reliable and automatic execution of destructors. The compiler's job is two-fold: Generate destructor calls in the normal execution flow of the program. Generate code that will call the necessary destructors to be run in the case of an exception.

Why is RAII good?

Smart pointers use RAII to hide the manipulation of pointers, which are a lower level than business code, so RAII helps respect levels of abstraction in that case too. This is true for resource management in general, including database connection.


2 Answers

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:

  1. IDisposable (and by extension using) was created exactly because there is no way to do that in .NET.
  2. 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.
like image 174
Jon Avatar answered Oct 06 '22 00:10

Jon


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.

like image 21
jeffora Avatar answered Oct 06 '22 01:10

jeffora