6

I want a class which will have a single method on its interface to add updates. These updates will be stored in an internal variable of the class until a specified batch size is reached. At that point all updates will be sent and the list of updates is cleared.

When my program is exiting, and there are still updates waiting to be sent out by my class, i could make another method on the interface to "SubmitRemaining". Or I could implement idisposable and not need consumers of this class to worry about implementation details. Would this be a valid usage of IDisposable, or is there another way I can do this?

  • 2
    I hope this doesn't stem from a misconception how the IDispose mechanism works. Dispose will neither be called when the program ends nor when the object gets garbage collected! When implementing IDisposable the user will still have to call the Dispose() method. – Roman Reiner Mar 20 '17 at 5:33
  • "When my program is exiting..." -> Just be aware that there are some "not so clean" ways to terminate a program in C#, and some of them won't even bother calling the garbage colector, which wouldn't even call any Finalize block, making your pending updates disappear through thin air. – Machado Mar 20 '17 at 14:01
  • 1
    If you are thinking you can complete your work when/if Dispose is called from finalize, you are headed down the wrong path. If you get that far, you can't access any managed members of your class as they may have already been garbage collected. – OldFart Mar 20 '17 at 14:31
6

The "official" purpose of IDisposable is to clean up unmanaged resources. Unmanaged resources are things like COM classes that can't be garbage-collected by the .NET runtime.

However, IDisposable (i.e. the Dispose() method) has also been used to:

  1. Close a managed stream,
  2. Execute an automatic callback,
  3. Write an ending HTML tag,
  4. Create an enclosing scope.

The only concern I have with some of these uses is that they don't convey the correct semantic meaning. The programmer coming after you that has to read your code will assume that IDisposable wraps something that requires disposal, or at least some sort of semantically meaningful cleanup. If you create unexpected side-effects with it, you will cause confusion.

I would therefore document in detail how the IDisposable interface is specifically implemented in your class definition (i.e. the XML comments), so that everyone is clear about exactly how it works in your specific context.

Further Reading
Abusing using statements
Example of creating scope with the using statement
Is there a better alternative than abusing the IDisposable pattern?
Is abusing IDisposable to benefit from “using” statements considered harmful?
Is it abusive to use IDisposable and “using” as a means for getting “scoped behavior”?

  • I think case in question falls into "close a stream" category. – Basilevs Mar 21 '17 at 9:39
2

On the face of it IDisposable is a good fit for batch processes.

If you are doing an single atomic process then you know at the start that you can close off your resources when done.

But with a batch process you may want to hold on to those open resources longer, while you process more things. In this case your processing code doesnt know when to close off its resources and you need to call Dispose explicitly.

However! The rest of your question implies that this is NOT what you want to use IDisposable for! It seems you want to have an automatic call to finish off processing the batch before the program quits.

This is not a good idea. There are many cases where this just wont work.

Plus, relying Dispose() or the close of a using statement to execute other functionality, although it has been used to do 'clever' tricks in the .net framework is just asking for trouble you dont need.

It sounds like you would be better off with some async Tasks or events to tell you when the batch is complete

One method I have used in a similar situation is to send the batch when either threshold count is reached OR a timer expires. This limits your exposure to situations where you have 9/10 items waiting to be sent for hours

0

Dispose seems like a nice pattern because it's guaranteed to be called in certain constructs, e.g.

using (var myCache = cacheFactory.GetCache())
{
    mycache.WriteData();
}

...will always end up calling Dispose.

But... what happens if something goes wrong with the commit? E.g. your disk is full or your database is down? Then you have to do this:

try
{
    using (var myCache = cacheFactory.GetCache())
    {
        mycache.WriteData();
    }
}
catch(SomeException ex)
{
    //What do I do now?  Is my object disposed or not?
}

That is why one of the rules for Dispose is

Don’t throw exceptions in Dispose. Nothing should go wrong with your object calling Dispose. Mainly for reasons stated above.

If the act of committing the cache could raise an exception, don't use Dispose. Create a new method named Flush() or something similar. Then your developer has more control over it and can do something like this:

try
{
    myCache.WriteData();
    myCache.Flush();
}
catch(SomeException ex)
{
    //Do something about it
}

If you really want, you can also implement Dispose as a back-stop, like this:

void Dispose()
{
    try
    {
        this.Flush();
    }
    catch
    {
        //Swallow exception
    } 
}

...which gives you the best of both worlds. Now you can write:

using (var myCache = cacheFactory.GetCache())
{
    try
    {
        mycache.WriteData();
        myCache.Flush();
    }
    catch(SomeException ex)
    {
        //Deal with it
    }
}

...but you're not totally hosed if someone forgets to call Flush.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.