1

I find myself doing this for a database object in my class:

if (Db != null)
{
    Db.Dispose();
    Db = null;
}

A few questions ...

  1. Should I have designed the Db object to have a shorter life, and so been able to put it in a using block?
  2. Is there a generic way of doing this, rather than writing 3 lines every time I dispose of something?

Those things aside, I am interested in whether something similar to this is possible:

static void SafeDispose(ref IDisposable obj)
{
    if (obj != null)
    {
        obj.Dispose();
        obj = null;
    }
}
noelicus
  • 14,468
  • 3
  • 92
  • 111
  • 1
    Like you mentioned, if the object implements IDisposible, you can use the using. For database stuff, I would recommend that you do use a using statement. – Justin Sep 25 '13 at 16:24
  • What is causing you to avoid using a using block? – Shawn Sep 25 '13 at 16:25
  • 1
    Is this code in the `Dispose()` method of the containing class? If so, this SO question is asking the same thing: [Disposing the members that implement IDisposable](http://stackoverflow.com/questions/3022650/disposing-the-members-that-implement-idisposable). It has a very good solution. Also if this is in the `Dispose()` method, you don't need to set `Db = null;` it provides no benefit. – Scott Chamberlain Sep 25 '13 at 16:45

3 Answers3

0
  1. Probably so. Without seeing more of your class it's impossible to say for certain. But as a rule of thumb, I try to avoid having fields or properties that are disposable (I assume that's how it is, since if it were a local variable, you could use using). It's too hard to manage them, unless your class is also IDisposable and you clean it up in your Dispose() method.
  2. You could refactor these lines into their own method, e.g. DisposeDb().
Tim S.
  • 55,448
  • 7
  • 96
  • 122
0
    public static void MyDispose(ref DbContext db)
    {
        if (db != null)
        {
            db.Dispose();
            db = null;
        }
    }

or something like that stuck in a class somewhere.

mp3ferret
  • 1,183
  • 11
  • 16
0
  1. Is there a generic way of doing this, rather than writing 3 lines every time I dispose of something?

To achieve something similar in a reusable fashion, you can create a static helper method:

public static class Disposable
{
    public static void Dispose(ref IDisposable obj)
    {
        if (obj!= null)
        {
            obj.Dispose();
            obj = null;
        }
    }
}

You can call the method like this:

Disposable.Dispose(ref someDisposableObject);

This is not going to work for properties because you cannot pass a property to a ref parameter. To make it work for Properties as well, you can use expressions:

public static class Disposable
{
    public static void Dispose(Expression<Func<IDisposable>> expression)
    {
        var obj = expression.Compile().Invoke();
        if (obj == null)
            return;

        obj.Dispose();

        var memberExpression = expression.Body as MemberExpression;
        if (memberExpression == null || !IsMemberWritable(memberExpression.Member))
            return;

        var nullExpression = Expression.Constant(null, memberExpression.Type);
        var assignExpression = Expression.Assign(memberExpression, nullExpression);
        var lambdaExpression = Expression.Lambda<Action>(assignExpression);

        var action = lambdaExpression.Compile();
        action.Invoke();
    }

    private static bool IsMemberWritable(MemberInfo memberInfo)
    {
        var fieldInfo = memberInfo as FieldInfo;
        if (fieldInfo != null)
            return !fieldInfo.IsInitOnly && !fieldInfo.IsLiteral;

        var propertyInfo = memberInfo as PropertyInfo;
        if (propertyInfo != null)
            return propertyInfo.CanWrite;

        return true;
    }
}

This method works with variables, fields and properties. It disposes any disposable object, but only sets it to null if it is writable.

You can dispose anything in the same way, as illustrated by the method Foo.CleanUp in the following example:

public class Bar : IDisposable
{
    // ...
}

public class Foo
{
    private Bar _barField = new Bar();

    public Bar BarProperty { get; set; } = new Bar();

    public void CleanUp()
    {
        Disposable.Dispose(() => _barField);
        Disposable.Dispose(() => BarProperty);

        var barVariable = new Bar();
        Disposable.Dispose(() => barVariable);
    }
}
lauxjpn
  • 4,749
  • 1
  • 20
  • 40