Using IDisposables with LINQ
Objects that implement IDisposable are everywhere. The interface even gets its own language features (C#, VB, F#). However, LINQ throws a few wrenches into things:
- LINQ’s query syntax depends on expressions; usingblocks are statements.
- When querying a sequence of IDisposableobjects, there’s no easy way to ensure disposal after each element has been consumed.
- Returning deferred queries from within a usingstatement is often desired, but fails spectacularly.
There are possible work-arounds for each issue…
- Put the using statement in a method (named or anonymous) that is called from the query. See also: Thinking Functional: Using.
- Use a method that creates a dispose-safe iterator of the sequence, like AsSafeEnumerable().
- Refactor the method to inject the IDisposabledependency, as shown in the first part of Marc’s answer here.
But, as you might have guessed, I would like to propose a better solution. The code is really complex, so bear with me:
public static IEnumerable<T> Use<T>(this T obj) where T : IDisposable
{
    try
    {
        yield return obj;
    }
    finally
    {
        if (obj != null)
            obj.Dispose();
    }
}
That’s it. We’re turning our IDisposable object into a single-element sequence. The trick is that the C# compiler will build an iterator for us that properly handles the finally clause, ensuring that our object will be disposed. It might be helpful to set a breakpoint on the finally clause to get a better idea what’s happening.
So how can this simple method solve all our problems? First up: “using” a FileStream object created in a LINQ query:
var lengths = from path in myFiles
              from fs in File.OpenRead(path).Use()
              select new { path, fs.Length };
Since the result of Use() is a single-element sequence, we can think of from fs in something.Use() as an assignment of that single value, something, to fs. In fact, it’s really quite similar to an F# use binding in that it will automatically clean itself up when it goes out of scope (by its enumerator calling MoveNext()).
Next, disposing elements from a collection. I’ll use the same SharePoint problem that AsSafeEnumerable() solves:
var webs = from notDisposed in site.AllWebs
           from web in notDisposed.Use()
           select web.Title;
I find this syntax rather clumsy compared with AsSafeEnumerable(), but it’s there if you need it.
Finally, let’s defer disposal of a LINQ to SQL DataContext until after the deferred query is executed, as an answer to the previously-linked Stack Overflow question:
IQueryable<MyType> MyFunc(string myValue)
{
    return from dc in new MyDataContext().Use()
           from row in dc.MyTable
           where row.MyField == myValue
           select row;
}
void UsingFunc()
{
    var result = MyFunc("MyValue").OrderBy(row => row.SortOrder);
    foreach(var row in result)
    {
        //Do something
    }
}
The result of MyFunc now owns its destiny completely. It doesn’t depend on some potentially disposed DataContext – it just creates one that it will dispose when it’s done. There are probably situations where you would want to share a DataContext rather than create one on demand (I don’t use LINQ to SQL, I just blog about it), but again it’s there if you need it.
I’ve only started using this approach recently, so if you have any problems with it please share.
