68

I was having a discussion with a colleague recently about the value of Dispose and types that implement IDisposable.

I think there is value in implementing IDisposable for types that should clean up as soon as possible, even if there are no unmanaged resources to clean up.

My colleague thinks differently; implementing IDisposable if you don't have any unmanaged resources isn't necessary as your type will eventually be garbage collected.

My argument was that if you had an ADO.NET connection that you wanted to close as soon as possible, then implementing IDisposable and using new MyThingWithAConnection() would make sense. My colleage replied that, under the covers, an ADO.NET connection is an unmanaged resource. My reply to his reply was that everything ultimately is an unmanaged resource.

I am aware of the recommended disposable pattern where you free managed and unmanaged resources if Dispose is called but only free unmanaged resources if called via the finalizer/destructor (and blogged a while ago about how to alert consumers of improper use of your IDisposable types)

So, my question is, if you've got a type that doesn't contain unmanaged resources, is it worth implementing IDisposable?

Steve Dunn
  • 21,044
  • 11
  • 62
  • 87
  • 2
    As you noted correctly, an ADO connection *is* an unmanaged resource. – Konrad Rudolph Apr 25 '12 at 17:36
  • 1
    @KonradRudolph - No. A Connection is called a _managed_ resource. It contains (owns) an unmanaged resource, though probably indirectly through a SafeHandle. – H H Apr 26 '12 at 11:05
  • @Henk That’s what I meant – I should have phrased this more carefully but in the question it’s already phrased in the correct way. – Konrad Rudolph Apr 26 '12 at 11:49
  • 2
    The only other time I've ever needed `IDisposable`, outside of unmanaged resources, is when I need to make sure that events get properly unsubscribed so a class can be garbage-collected. But that is really a failure of the language: events really REALLY **_REALLY_** need to be weak-references, but they're not. – BlueRaja - Danny Pflughoeft Jul 05 '12 at 20:45

15 Answers15

36

There are different valid uses for IDisposable. A simple example is holding an open file, which you need to be closed at certain moment, as soon as you don't need it any more. Of course, you could provide a method Close, but having it in Dispose and using pattern like using (var f = new MyFile(path)) { /*process it*/ } would be more exception-safe.

A more popular example would be holding some other IDisposable resources, which usually means that you need to provide your own Dispose in order to dispose them as well.

In general, as soon as you want to have deterministic destruction of anything, you need to implement IDisposable.

The difference between my opinion and yours is that I implement IDisposable as soon as some resource needs deterministic destruction/freeing, not necessary as soon as possible. Relying on garbage collection is not an option in this case (contrary to your colleague's claim), because it happens at unpredictable moment of time, and actually may not happen at all!

The fact that any resource is unmanaged under the cover really doesn't mean anything: the developer should think in terms of "when and how is it right to dispose of this object" rather than "how does it work under the cover". The underlying implementation may change with the time anyway.

In fact, one of the main differences between C# and C++ is the absence of default deterministic destruction. The IDisposable comes to close the gap: you can order the deterministic destruction (although you cannot ensure the clients are calling it; the same way in C++ you cannot be sure that the clients call delete on the object).


Small addition: what is actually the difference between the deterministic freeing the resources and freeing them as soon as possible? Actually, those are different (though not completely orthogonal) notions.

If the resources are to be freed deterministically, this means that the client code should have a possibility to say "Now, I want this resource freed". This may be actually not the earliest possible moment when the resource may be freed: the object holding the resource might have got everything it needs from the resource, so potentially it could free the resource already. On the other hand, the object might choose to keep the (usually unmanaged) resource even after the object's Dispose ran through, cleaning it up only in finalizer (if holding the resource for too long time doesn't make any problem).

So, for freeing the resource as soon as possible, strictly speaking, Dispose is not necessary: the object may free the resource as soon as it realizes itself that the resource is not needed any more. Dispose however serves as a useful hint that the object itself is not needed any more, so perhaps the resources may be freed at that point if appropriate.


One more necessary addition: it's not only unmanaged resources that need deterministic deallocation! This seems to be one of key points of the difference in opinions among the answers to this question. One can have purely imaginative construct, which may need to be freed deterministically.

Examples are: a right to access some shared structure (think RW-lock), a huge memory chunk (imagine that you are managing some of the program's memory manually), a license for using some other program (imagine that you are not allowed to run more than X copies of some program simultaneously), etc. Here the object to be freed is not an unmanaged resource, but a right to do/to use something, which is a purely inner construct to your program logic.


Small addition: here is a small list of neat examples of [ab]using IDisposable: http://www.introtorx.com/Content/v1.0.10621.0/03_LifetimeManagement.html#IDisposable.

Vlad
  • 35,022
  • 6
  • 77
  • 199
  • 2
    When would you ever need to have deterministic destruction, outside of unmanaged resources like files and DB-connections? *(also minor gripe - the object itself is not deterministically destructed, only the resources it uses... and only if those resources are unmanaged)* – BlueRaja - Danny Pflughoeft Apr 25 '12 at 17:56
  • @BlueRaja-DannyPflughoeft: See my answer, but to answer directly: 1) When you're using those resources indirectly by other objects that implement `IDisposable`, or when the `IDisposable` idiom (and the convenience of the `using` block) are of use for whatever reason. – Adam Robinson Apr 25 '12 at 18:23
  • @Adam: Case 1 is exactly the case when there are unmanaged resources to clean up. Case 2 is orthogonal to my question, and isn't a real example anyways. – BlueRaja - Danny Pflughoeft Apr 25 '12 at 19:31
  • @BlueRaja-DannyPflughoeft: True, though the pattern is different depending on whether you're using the unmanaged resources directly or through an abstraction. As to the second, Any pattern where you have an entry and exit point is suitable. While `lock` already exists, it would be easy to reproduce the same sort of behavior with `using`. It can also be useful for things where you're temporarily changing state and want to ensure that it gets changed back...changing the mouse cursor, for example. You'd change it in the constructor and reset it to whatever it was in `Dispose`. – Adam Robinson Apr 25 '12 at 19:37
  • @BlueRaja: any resource may need deterministic deallocation. It might be a slot in a task table, huge memory chunk, token in the ring queue of cooperative workers, whatever. – Vlad Apr 26 '12 at 11:07
  • @BlueRaja-DannyPflughoeft: I wish people would say "unmanaged resources like files etc." since it's possible to have things entirely within the managed-code universe which need deterministic cleanup. Things like locks and strong events are resources which require non-GC-based cleanup, but they don't access anything outside the managed Framework. – supercat Oct 27 '15 at 16:42
  • @supercat: Releasing a lock and reclaiming its resources are not the same thing. Neither locks nor strong events require deterministic destruction. – BlueRaja - Danny Pflughoeft Oct 27 '15 at 20:02
  • 2
    @BlueRaja-DannyPflughoeft: Exclusive access to a locked object *is* a resource; if the an object holding the right to exclusive access is abandoned without notifying the guarded object that exclusivity is no longer required, then nobody will be able to use the object anymore. As for events, if an unbounded number of short-lived objects subscribe to events from a long-lived object but are abandoned soon thereafter, such objects will create an unbounded memory leak since they won't become eligible for collection during the lifetime of the longer-lived object. – supercat Oct 27 '15 at 20:30
17

I think it's most helpful to think of IDisposable in terms of responsibilities. An object should implement IDisposable if it knows of something that will need to be done between the time it's no longer needed and the end of the universe (and preferably as soon as possible), and if it's the only object with both the information and impetus to do it. An object which opens a file, for example, would have a responsibility to see that the file gets closed. If the object were to simply disappear without closing the file, the file might not get closed in any reasonable timeframe.

It's important to note that even objects which only interact with 100% managed objects can do things that need to be cleaned up (and should use IDisposable). For example, an IEnumerator which attaches to a collection's "modified" event will need to detach itself when it is no longer needed. Otherwise, unless the enumerator uses some complex trickery, the enumerator will never be garbage-collected as long as the collection is in scope. If the collection is enumerated a million times, a million enumerators would get attached to its event handler.

Note that it's sometimes possible to use finalizers for cleanup in cases where, for whatever reason, an object gets abandoned without Dispose having been called first. Sometimes this works well; sometimes it works very badly. For example, even though Microsoft.VisualBasic.Collection uses a finalizer to detach enumerators from "modified" events, attempting to enumerate such an object thousands of times without an intervening Dispose or garbage-collection will cause it to get very slow--many orders of magnitude slower than the performance that would result if one used Dispose correctly.

Steve Dunn
  • 21,044
  • 11
  • 62
  • 87
supercat
  • 77,689
  • 9
  • 166
  • 211
  • 1
    Thanks, I wish I thought of the IEnumerator example as a retort! – Steve Dunn Apr 25 '12 at 13:54
  • 2
    @SteveDunn: Thanks. There seems to be a widespread belief that the term "unmanaged" in the phrase "unmanaged resources" has something to do with "unmanaged code". The reality is that the two concepts are largely orthogonal. Finalizers can somewhat confuse the "cleanup responsibility" issue, since without them the "before the end of the universe" language could be somewhat literal. If an object without a finalizer holds the only copy of a handle granting exclusive access to something and it gets abandoned without releasing the handle, the handle will literally *never* get released. – supercat Apr 25 '12 at 14:45
  • 1
    @SteveDunn: Of course, the question of whether the handle ever got released may become moot well before the end of the universe, but the key point is that once all copies of it are gone, nothing will ever release the handle. Therefore, the last entity with a copy of it must ensure that it gets released while that copy of the handle still exists. Incidentally, another good example of an "unmanaged resource" entirely within managed code: locks. – supercat Apr 25 '12 at 14:47
  • `even objects which only interact with 100% unmanaged objects` Shouldn't that read 100% MANAGED objects? Otherwise, great answer. If your implemenation owns an instance which is IDisposable, you should implement it as well to clean it up, and IDisposable is the only way to communicate that. – Andy Apr 25 '12 at 16:46
  • @Andy: Fixed. My main point is that a lot of people seem to think that the phrase "unmanaged resource" means "resource handled by native code", when that isn't really true. While resources managed by native code are almost always unmanaged resources, they are hardly the only important type. Actually, I really dislike the terms "managed resources" and "unmanaged resources", because there's so little consistency in what they mean. Is something which doesn't manipulate anything outside itself a "managed resource", or is does that term only refer to objects with finalizers? – supercat Apr 25 '12 at 17:05
  • FWIW, I'm not aware of any enumerators that monitor the collection in this manner. The enumerator for `List`, for example, just checks the `version` variable in the list. But a valid point, nonetheless. – Adam Robinson Apr 25 '12 at 19:41
  • @AdamRobinson: The `Microsoft.VisualBasic.Collection` class' enumerator subscribes to notifications when the collection is modified, and uses those notifications so it can continue to behave sensibly. The `Collection` class does include logic to ensure that if an enumerator is abandoned the subscriptions will get cleaned up at the next GC, but if one enumerates a `Collection` many (e.g. thousands) of times between garbage-collection cycles, it will start to get very slow. Once the next collection occurs, it will speed back up. – supercat Apr 25 '12 at 22:44
  • @supercat: Interesting! Yet another reason to dispose `IDisposable`s – Adam Robinson Apr 26 '12 at 01:35
  • @AdamRobinson: Incidentally, while the aforementioned `Collection` object has some annoying quirks that limit its usefulness for purposes other than historical compatibility, it also have some unique advantages. Chief among them, it was the only dictionary-ish collection which made it easy to remove all items meeting a certain criterion, without having to build up a separate list of items to remove. – supercat Apr 26 '12 at 14:47
9

So, my question is, if you've got a type that doesn't contain unmanaged resources, is it worth implementing IDisposable?

When someone places an IDisposable interface on an object, this tells me that the creator intends on this either doing something in that method or, in the future they may intend to. I always call dispose in this instance just to be sure. Even if it doesn't do anything right now, it might in the future, and it sucks to get a memory leak because they updated an object, and you didn't call Dispose when you were writing code the first time.

In truth it's a judgement call. You don't want to over implement it, because at that point why bother having a garbage collector at all. Why not just manually dispose every object. If there is a possibility that you'll need to dispose unmanaged resources, then it might not be a bad idea. It all depends, if the only people using your object are the people on your team, you can always follow up with them later and say, "Hey this needs to use an unmanaged resource now. We have to go through the code and make sure we've tidied up." If you are publishing this for other organizations to use that's different. There is no easy way to tell everyone who might have implemented that object, "Hey you need to be sure this is now disposed." Let me tell you there are few things that make people madder than upgrading a third party assembly to find out that they are the ones who changed their code and made your application have run away memory problems.

My colleage replied that, under the covers, an ADO.NET connection is a managed resource. My reply to his reply was that everything ultimately is an unmanaged resource.

He's right, it's a managed resource right now. Will they ever change it? Who knows, but it doesn't hurt to call it. I don't try and make guesses as to what the ADO.NET team does, so if they put it in and it does nothing, that's fine. I'll still call it, because one line of code isn't going to affect my productivity.

You also run into another scenario. Let's say you return an ADO.NET connection from a method. You don't know that ADO connection is the base object or a derived type off the bat. You don't know if that IDisposable implementation has suddenly become necessary. I always call it no matter what, because tracking down memory leaks on a production server sucks when it's crashing every 4 hours.

kemiller2002
  • 113,795
  • 27
  • 197
  • 251
  • Many types implement `IDisposable` not because they expect a future version might do so, but because they or a base type may be used as the return type for factory methods that may return derived types that do require cleanup. All types that implement `IEnumerator`, for example, implement `IDisposable` even though the vast majority of their `Dispose` methods do nothing. – supercat Nov 03 '15 at 00:39
6

While there are good answers to this already, I just wanted to make something explicit.

There are three cases for implementing IDisposable:

  1. You are using unmanaged resources directly. This typically involves retrieving an IntPrt or some other form of handle from a P/Invoke call that has to be released by a different P/Invoke call
  2. You are using other IDisposable objects and need to be responsible for their disposition
  3. You have some other need of or use for it, including the convenience of the using block.

While I might be a bit biased, you should really read (and show your colleague) the StackOverflow Wiki on IDisposable.

Community
  • 1
  • 1
Adam Robinson
  • 182,639
  • 35
  • 285
  • 343
  • 2
    I recommend updating the Wiki to include *lifetime management* as a reason to implement `IDisposable`. For example, `IObservable.Subscribe` returns an `IDisposable` even though it is not intended to encapsulate unmanaged resources or be used in `using` blocks. – Gabe Apr 25 '12 at 20:23
  • 1
    @Gabe: It's a wiki, so feel free to edit. I haven't used `IObservable` before, so it might be better if you could add something. – Adam Robinson Apr 25 '12 at 20:41
  • 1
    @AdamRobinson: There should be some clarification about "always" call `IDisposable`. It's important that `Dispose` be called before the last reference to an `IDisposable` is destroyed (since it can't be called after). On the other hand, it's common for many objects to hold references to an `IDisposable`; generally, exactly one should call `Dispose`. – supercat Apr 26 '12 at 14:55
  • @supercat: Yes, you're correct. There should be one "owner" for any given `IDisposable` that is responsible for ensuring that `Dispose` gets called appropriately. – Adam Robinson Apr 26 '12 at 15:08
5

No, it's not only for unmanaged resources.

It's suggested like a basic cleanup built-in mechanism called by framework, that enables you possibility to cleanup whatever resource you want, but it's best fit is naturally unmanaged resources management.

H H
  • 263,252
  • 30
  • 330
  • 514
Tigran
  • 61,654
  • 8
  • 86
  • 123
  • Implementing (and calling) Dispose is critical for most resource-holding classes. managed/unmanaged is mostly irrelevant. – H H Apr 26 '12 at 11:08
  • @HenkHolterman: to *me* it seems what I *exactly* mean: "it's not only for unamanaged resources management." Isn't it? – Tigran Apr 26 '12 at 11:11
  • 1
    Yes, sorry. I overlooked a __not__ in there. – H H Apr 26 '12 at 11:15
5

Note that unmanaged resources may well include standard CLR objects, for instance held in some static fields, all ran in safe mode with no unmanaged imports at all.

There is no simple way to tell if a given class implementing IDiposable actually needs to clean something. My rule of thumb is to always call Dispose on objects I don't know too well, like some 3rd party library.

Jacek Gorgoń
  • 3,206
  • 1
  • 26
  • 43
  • It's worth noting that if even if an object had a `DisposeRequired` property, the time required to find out whether `Dispose` was necessary would (slightly) exceed the time required to call `Dispose` unconditionally [since it would have to make a virtual call to the property and then branch on the result, as opposed to simply making a virtual call]. The only time `DisposeRequired` would be helpful would be if determining *when* to call `Dispose` would be more onerous than actually calling it (e.g. if a "user count" would be needed on objects requiring cleanup, but not on those that don't). – supercat Dec 25 '13 at 20:42
5

Dispose should be used for any resource with a limited lifetime. A finalizer should be used for any unmanaged resource. Any unmanaged resource should have a limited lifetime, but there are plenty of managed resources (like locks) that also have limited lifetimes.

Gabe
  • 84,912
  • 12
  • 139
  • 238
3

If you aggregate IDisposables then you should implement the interface in order that those members get cleaned up in a timely way. How else is myConn.Dispose() going to get called in the ADO.Net connection example you cite?

I don't think it's correct to say that everything is an unmanaged resource in this context though. Nor do I agree with your colleague.

Steve Townsend
  • 53,498
  • 9
  • 91
  • 140
3

You are right. Managed database connections, files, registry keys, sockets etc. all hold on to unmanaged objects. That is why they implement IDisposable. If your type owns disposable objects you should implement IDisposable and dispose them in your Dispose method. Otherwise they may stay alive until garbage collected resulting in locked files and other unexpected behavior.

Martin Liversage
  • 104,481
  • 22
  • 209
  • 256
  • Er, it sounds like you are agreeing with OP's colleague, not with OP. – BlueRaja - Danny Pflughoeft Apr 25 '12 at 18:01
  • Well, I assume that the colleague argues that if your type has an managed ADO connection it doesn't have to implement `IDisposable` because the resource is managed. What I say is that you have to because deep inside any `IDisposable` object there is an unmanaged resource. When you aggregate `IDisposable` objects you also have to implement `IDisposable`. – Martin Liversage Apr 25 '12 at 18:22
  • In that case, there are unmanaged resources to clean up. The colleague is arguing that if there are no unmanaged resources, there is no need for `IDisposable` - OP seems to think that *"there is value in implementing `IDisposable` [..] even if there are no unmanaged resources to clean up."* – BlueRaja - Danny Pflughoeft Apr 25 '12 at 19:29
  • @BlueRaja-DannyPflughoeft: I guess the question is somewhat ambigouous. My question was mainly a response to _My reply to his reply was that everything ultimately is an unmanaged resource._ I'm backing that claim. – Martin Liversage Apr 25 '12 at 19:36
3

everything ultimately is an unmanaged resource.

Not true. Everything except memory used by CLR objects which is managed (allocated and freed) only by the framework.

Implementing IDisposable and calling Dispose on an object that does not hold on to any unmanaged resources (directly or indirectly via dependent objects) is pointless. It does not make freeing that object deterministic because you can't directly free object's CLR memory on your own as it is always only GC that does that. Object being a reference type because value types, when used directly at a method level, are allocated/freed by stack operations.

Now, everyone claims to be right in their answers. Let me prove mine. According to documentation:

Object.Finalize Method allows an object to try to free resources and perform other cleanup operations before it is reclaimed by garbage collection.

In other words object's CLR memory is released just after Object.Finalize() is called. [note: it is possible to explicitly skip this call if needed]

Here is a disposable class with no unmanaged resources:

internal class Class1 : IDisposable
{
    public Class1()
    {
        Console.WriteLine("Construct");
    }

    public void Dispose()
    {
        Console.WriteLine("Dispose");
    }

    ~Class1()
    {
        Console.WriteLine("Destruct");
    }
}

Note that destructor implicitly calls every Finalize in the inheritance chain down to Object.Finalize()

And here is the Main method of a console app:

static void Main(string[] args)
{
    for (int i = 0; i < 10; i++)
    {
        Class1 obj = new Class1();
        obj.Dispose();
    }

    Console.ReadKey();
}

If calling Dispose was a way to free a managed object in a deterministic way, every "Dispose" would be immediately followed by a "Destruct", right? See for yourself what happens. It is most interesting to run this app from a command line window.

Note: There is a way to force GC to collect all objects which are pending finalization in the current app domain but no for a single specific object. Nevertheless you do not need to call Dispose to have an object in the finalization queue. It is strongly discouraged to force collection as it will likely hurt overall application performance.

EDIT

There is one exception - state management. Dispose can handle state change if your object happens to manage an outside state. Even if state is not an unmanaged object it is very convenient to use it like one because of special treatment IDisposable has. Example would be a security context or impersonation context.

using (WindowsImpersonationContext context = SomeUserIdentity.Impersonate()))
{
    // do something as SomeUser
}

// back to your user

It is not the best example because WindowsImpersonationContext uses system handle internally but you get the picture.

Bottom line is that when implementing IDisposable you need to have (or plan to have) something meaningful to do in the Dispose method. Otherwise it's just a waste of time. IDisposable does not change how your object is managed by GC.

Maciej
  • 7,871
  • 1
  • 31
  • 36
  • 1
    You are not right here. The object may be not "physically" garbage collected, but logically it will free something important at the known time. This "something" may be not only some unmanaged resource, but also a slot in the queue, allocation of a threadpool thread for some calculation, license for using some other program etc. -- i.e., a _logical_ resource. The presence of the object in memory is a pure detail and shouldn't be taken into account if the disposable object is implemented in the right way. – Vlad May 02 '12 at 09:37
  • @Vlad You missed some parts of my answer. All those "something" you mentioned are in the end unmanaged resources. If your object deals with those (directly or indirectly via dependent objects) it becomes an unmanaged one and should implement `Dispose`. In other words if any dependent object implements `Dispose` your object should as well. Sorry if that was not clearly pointed. – Maciej May 02 '12 at 10:13
  • 1
    Well, I am not questioning the whole of your answer, it's just the part "calling Dispose on an object that does not hold on to any unmanaged resources (...) is pointless". I tried to get some examples where the resource is essentially managed, though needs to be freed in a deterministic way. For example, the _right to modify a collection_ is clearly not an unmanaged resource, but obtaining this right in a [RAII-way](http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization) with `IDisposable` is a good thing: `using (ObtainModifyRight(collection)) { /* modify it */ }`. – Vlad May 02 '12 at 11:04
  • 1
    Managing state using Dispose is a bit of hijacking dispose pattern as it is meant for unmanaged resources. But I agree this sometimes happens and is convenient because because of `using` keyword. Updating answer. – Maciej May 02 '12 at 12:40
  • The right to modify a collection is an unmanaged resource if the bestowal of such right on one object will impair other objects' ability to modify that collection until the object which received such right indicates it is no longer needed. After all, what does it really mean for an object to request a block of unmanaged memory from the operating system, except that (1) the OS gives the object the right to use that memory, and (2) nobody else will be able to use it until the first object tells the OS it no longer needs it? – supercat Jun 19 '12 at 19:16
  • @Maciej - as far as the "pointless" comment goes, maybe you should read my other explanations to other posts I've linked my answer to. As far as "proving" your answer, documentation is one thing, but unless you've debugged OOM exception memory dumps with WinDbg and have knowledge on the internal workings of the GC, you should rely on experience more than documentation. – Dave Black Sep 04 '12 at 22:48
1

Your Type should implement IDisposable if it references unmanaged resources or if it holds references to objects that implement IDisposable.

justin.m.chase
  • 13,061
  • 8
  • 52
  • 100
1

In one of my projects I had a class with managed threads inside it, we'll call them thread A, and thread B, and an IDisposable object, we'll call it C.

A used to dispose of C on exiting. B used to use C to save exceptions.

My class had to implement IDisposable and a descrtuctor to ensure things are disposed of in the correct order. Yes the GC could clean up my items, but my experience was there was a race condition unless I managed the clean up of my class.

M Afifi
  • 4,645
  • 2
  • 28
  • 48
1

Short Answer: Absolutely NOT. If your type has members that are managed or unmanaged, you should implement IDisposable.

Now details: I've answered this question and provided much more detail on the internals of memory management and the GC on questions here on StackOverflow. Here are just a few:

As far as best practices on the implementation of IDisposable, please refer to my blog post:

How do you properly implement the IDisposable pattern?

Community
  • 1
  • 1
Dave Black
  • 7,305
  • 2
  • 52
  • 41
1

Implement IDisposable if the object owns any unmanaged objects or any managed disposable objects

If an object uses unmanaged resources, it should implement IDisposable. The object that owns a disposable object should implement IDisposable to ensure that the underlying unmanaged resources are released. If the rule/convention is followed, it is therefore logical to conclude that not disposing managed disposable objects equals not freeing unmanaged resources.

Igor Pashchuk
  • 2,455
  • 2
  • 22
  • 29
1

Not necessary resources at all (either managed or unmanaged). Often, IDisposable is just a convenient way to elimnate combersome try {..} finally {..}, just compare:

  Cursor savedCursor = Cursor.Current;

  try {
    Cursor.Current = Cursors.WaitCursor;

    SomeLongOperation();
  }
  finally {
    Cursor.Current = savedCursor;
  }

with

  using (new WaitCursor()) {
    SomeLongOperation();
  }

where WaitCursor is IDisposable to be suitable for using:

  public sealed class WaitCursor: IDisposable {
    private Cursor m_Saved;

    public Boolean Disposed {
      get;
      private set;
    }

    public WaitCursor() {
      Cursor m_Saved = Cursor.Current;
      Cursor.Current = Cursors.WaitCursor;
    }

    public void Dispose() {
      if (!Disposed) {
        Disposed = true;
        Cursor.Current = m_Saved;
      }
    }
  }

You can easily combine such classes:

  using (new WaitCursor()) {
    using (new RegisterServerLongOperation("My Long DB Operation")) {
      SomeLongRdbmsOperation();  
    }

    SomeLongOperation();
  }
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215