65.9K
CodeProject is changing. Read more.
Home

RAII (Resource Acquisition Is Initialization) C# Helper Classes

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.64/5 (14 votes)

Oct 28, 2010

CPOL

3 min read

viewsIcon

46780

Some useful RAII C# helper classes for functionality that does not implement IDisposable

Introduction

What the Heck is RAII?

RAII stands for "Resource Acquisition Is Initialization". It is a programming idiom which ensures that there is no resource leak (like lost memory, open handles, dangling critical section monitors, etc.), even if an exception is thrown. For languages like C#, the lost memory is not of an issue, but the problem of "open handles" and "critical section monitors" is equally important.

Some languages provide a mechanism to deterministically and implicitly call one specific function at the end of the lifetime of an object instance (e.g. the destructor in C++). The RAII idiom in C++ takes benefit of that fact and places the "acquisition" of the resource into the constructor (= initialization), and releases the resource in the destructor.

E.g. the C++ auto pointer as well as any guard or sentry classes are implementing the RAII idiom. For more insight, see RAII Idiom.

In C++, a reporting sentry (RAII class) would log the text in its constructor and log again some text in its destructor (that is called when leaving the function body):

// this is C++ use of an RAII class
void f()
{
   ReportSentry reportSentry("function f");
   ...
}

C# does not know this deterministic and implicit destructor call, that's why I explain how I approach this issue in C#.

RAII in the C# World

Coming from a C++ background, I often did apply the RAII idiom. This was not only used for resources but for any kind of action that required symmetric "open-close", "add-remove", "set-reset", "open tag - close tag", "enter critical section - leave critical section", "report start-of-function - report end-of-function", etc. actions - no matter how the control flow left the current scope.

C# provides the well known IDisposable interface. Each class that implements this interface can be considered as "RAII-ready", i.e., one can use an instance of this class in a...

using (...) { ... }

...statement.

But what to do if you have the need of RAII, but no class at hand for the using (...) { ... } statement?

This article shows some simple helper classes that provide an IDisposable wrapper class for an init and a cleanup delegate.

Of course, this is not at all rocket science - actually, it is very simple. It should help to clear up the mist of exception handling involved and focus on the normal control flow.

Using the Code

First, I show the two usages of RAII versus hand crafted side by side.

With RAII support classes Hand crafted
using (var objGuard = new RAIIGuard<int>(
                  () =>objStack.Pop(),
                  (e)=>objStack.Push(e)))
{
    ...
    if (objGuard.Item != 0)
    {
        return;
    }    
    ...
    if (...)
    {
         throw new ...;
    }
    ...
}
int iTaken;
bool bTaken = false;
try
{
    // access the taken object
    iTaken = objStack.Pop();
    bTaken = true; 
    ...
    if (iTaken == 0)
    {
        return;
    }    
    ...
    if (...)
    {
         throw new ...;
    }
    ...
}
finally
{
    if (bTaken)
    {
        objStack.Push(iTaken);
    }
}

I consider the RAII supported approach more legible. If the lambda expressions hurt your eyes, you can always use delegates or methods, e.g.

private int Pop() { return Stack.Pop(); }
private void Push(int i) { Stack.Push(i); }
using (var objGuard = new RAIIGuard<int>(Pop, Push)) 
{
   ...
}

Conveniently, there are two classes to provide that function:

  1. one that has an init action and a cleanup action (e.g. login, logout)
  2. one that has an init function returning an object and a cleanup function taking that object (e.g. login and logout with a session object)
// used for symmetric actions like login, logout
public sealed class RAIIGuard: IDisposable
{
    private Action Cleanup { get; set; }
    public RAIIGuard(Action init, Action cleanup)
    {
        Cleanup = cleanup;
        if (init != null) init();
    }
    void IDisposable.Dispose() { if (Cleanup != null) Cleanup(); }
]
// used for symmetric actions that must pass
// over an object from init to cleanup and that
// need to provide the item to the "using" body
public sealed class RAIIGuard<T>: IDisposable
{
    private Action<T> Cleanup { get; set; }
    public T Item { get; private set; }
    public RAIIGuard(Func<T> init, Action<T> cleanup)
    {
        Cleanup = cleanup;
        Item = (init != null) ? init() : default(T);
    }
    void IDisposable.Dispose() { if (Cleanup != null) Cleanup(Item); }
]

Conclusion

It would still be nice if the committee "guarding" ;-) the C# language could re-consider to implement a native RAII support (e.g. where one can declare a guard as an instance of some kind of "value" type and at the end of the scope, a "Dispose" method is implicitly and deterministically called).

The approach above still requires a certain amount of cooperation by the client where as the pure RAII solution would not need cooperation by the client, i.e., in C#, one can still screw up the RAII idiom by not calling the Dispose() method :-( .

In the meantime, the approach shown above is good enough for me...

History

  • 2010-10-27 Initial version
  • 2010-10-27 Fixed some typos
  • 2010-10-29 Added more background on RAII, explicit implementation of Dispose() (Thanks to Roberto Collina)