SafeUsingBlock and DisposableWrapper Tutorial

This tutorial aims to teach you about the SafeUsingBlock and DisposableWrapper constructs that can be found in DigitallyCreated.Utilities.Bcl. It assumes you already know C#.

SafeUsingBlock

The standard C# using block has the potential to silently swallow thrown exceptions; the SafeUsingBlock construct works similarly to a C# using block, but doesn't suffer from this flaw. The using block flaw and SafeUsingBlock is discussed in this blog post.

DisposableWrapper

The DisposableWrapper<T> class is a small utility that can wrap any object type in a class that is IDisposable. If the wrapped object is IDisposable itself, then when the wrapper is disposed, the wrapped object is too. But if the wrapped object is not IDisposable, then disposing the wrapper doesn't do anything.

This is useful in cases where you have a reference to an interface which doesn't implement IDisposable, however, the underlying concrete class may or may not (depending on the implementation) implement IDisposable. You'd like to use that interface inside a C# using block (or a SafeUsingBlock), but you can't unless you do a runtime type check and cast, which is messy. DisposableWrapper solves this problem.

Imagine you had an IWorldSaver interface and two IWorldSaver implementations WorldSaver and DisposableWorldSaver:

public interface IWorldSaver
{
    void SaveWorld();
}

public class DisposableWorldSaver : IWorldSaver, IDisposable
{
    public void SaveWorld() { ... }
    public void Dispose() { ... }
}

public class ConcreteWorldSaver : IWorldSaver
{
    public void SaveWorld() { ... }
}

Then imagine you have a method that is called with a new IWorldSaver, constructed by some factory or dependency injection. That method knows that some IWorldSaver implementations are IDisposable and therefore wants to use a using block; so it uses a DisposableWrapper to do this:

void SaveTheWorld(IWorldSaver worldSaver)
{
    using (DisposableWrapper<IWorldSaver> wrapper = DisposableWrapper.New(worldSaver))
    {
        wrapper.Object.SaveWorld();
    }
}

If you want to use a SafeUsingBlock, the syntax is even nicer, as a special SafeUsingBlock method will unwrap the wrapper for you:

void SaveTheWorld(IWorldSaver worldSaver)
{
    DisposableWrapper.SafeUsingBlock(worldSaver, ws =>
    {
        ws.SaveWorld();
    });
}

Of course, this is a simplistic and contrived example. A real-world place where you need a DisposableWrapper is where you use a WCF client through its interface. The interface doesn't implement IDisposable, but the underlying WCF client class does. DisposableWrapper can help you there.

Last edited Mar 5, 2010 at 4:42 AM by dchambers, version 1

Comments

No comments yet.