Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Yielding with an IDisposable resource

Is there a proper way to yield through a disposable resource? The returned objects are IDisposable, but the element it is iterating through is.

Here is an example:

public static IEnumerable<T> Fetch(IEnumerable<Guid> ids)
{
    using (var client = new CouchbaseClient())
    {
        yield return ids.Select(s => s.ToString());
    }
}

Right now, calling this would not dispose the using resource obtained. I know I can just to a ToList and return it all at once, but is there a way to handle this "properly", or do I have to keep a tab on the IDisposable resource and dispose of it manually when I'm done?

like image 309
Jess Avatar asked Nov 22 '12 01:11

Jess


People also ask

When should you use IDisposable?

If you access unmanaged resources (e.g. files, database connections etc.) in a class, you should implement IDisposable and overwrite the Dispose method to allow you to control when the memory is freed.

What happens if you dont Dispose IDisposable?

The code in the finally block checks that the object that implements IDisposable isn't null before it calls the Dispose method. Failure to do this can result in a NullReferenceException exception at run time.

How does IDisposable work?

In a nutshell, an IDisposable class allows you to explicitly handle the deallocation of resources (typically unmanaged resources or database connections) via the Dispose() method. IDisposable class instances should be created within a "Using" block so as to ensure that the Dispose method is actually called.

What is IDisposable?

IDisposable is an interface that contains a single method, Dispose(), for releasing unmanaged resources, like files, streams, database connections and so on.


1 Answers

In short, you don't need to worry about it as long as the caller of the method handles the IEnumerator objects properly.

IEnumerator implementes IDisposable, and the logic used in creating the iterator blocks is actually smart enough to execute all un-executed finally blocks when it is disposed. A finally block is created as a result of the using call, and that is where the IDisposable resource is disposed.

So as long as the IEnumerator objects created from this IEnumerable are either iterated fully (in which case the final MoveNext call will reach the end of the using block and dispose of the resource) or disposed the IDisposable client will be disposed.

Note that if you're concerned the user of your code may not treat the IEnumerator objects properly then you're best bet is to not use an iterator block with lazy evaluation. If you want to ensure that even if the caller doesn't "play nice" then eagerly evaluate the method (i.e. take the code you have, dump the results into a list, and then return that list). If the consequences of not disposing the resource are primarily, or entirely performance related (not releasing some memory for a while longer, keeping open a connection, etc.) then it may not be a concern, but if holding onto the lock forever is a major problem (i.e. a locked resource that could result in deadlocks if not released) then the advantage of lazy evaluation may not be worth it.

like image 124
Servy Avatar answered Nov 03 '22 14:11

Servy