17

I have seen so many times developers using a disposable object inline, here for instance. By inline I mean:

var result = new DataTable().Compute("1 + 4 * 7", null);

I know that the Dispose method won't be called, but since no reference is held to the object, how will the garbage collector handle it? Is it safe to use a disposable object like that?

I used a DataTable in my example because it is the only concrete example I found, but my question applies to disposable objects in general. I do not personally use them like that, I just wanted to know if they are handled diffently by the GC if they are used that way.

Community
  • 1
  • 1
Fabien ESCOFFIER
  • 4,751
  • 1
  • 20
  • 32
  • Although this doesn't answer your general question, it does speak to your example http://stackoverflow.com/questions/913228/should-i-dispose-dataset-and-datatable – hatchet - done with SOverflow Apr 23 '16 at 21:16
  • 4
    That snippet was written by a smart programmer that knew that DataTable does not have anything disposable and does not actually implement Dispose(). Lots of .NET programmers are very uncomfortable about that. So just don't do it that way, it doesn't get a lot uglier when you use the *using* statement. You can feel good about never being wrong. – Hans Passant Apr 23 '16 at 22:11

3 Answers3

11

The key problem here is the timing when Dispose is called, which is just unknown in your example (providing a good implementation of IDisposable — see below). I'd consider using an IDisposable instance without a using statement a code smell. The class is implementing IDisposable for a reason, and thus you as a user should obey its contract.

However, note that in a correct implementation of IDisposable the class'es finalizer handles the disposal of an un-disposed object. Hence even if not instantiated within a using, the disposal shall be performed, but in unknown time and on a different (the GC's) thread.

I just wanted to know if they are handled diffently by the GC if they are used that way.

No, the GC treats all object alike and doesn't treat IDisposable implementations anyhow differently. However, in a correct implemenetation of IDisposable the Finalize method (invoked by the GC on every object unless suppressed on a per-object basis) call would lead to invoking the Dispose.

Ondrej Tucny
  • 27,626
  • 6
  • 70
  • 90
1

If the object that is being initialized inline has a destructor implemented, that destructor could be calling Dispose() after the object has gone out of scope.

However, the cleaner and correct way is to use a using statement because this could potentially lead to just instances of objects hanging around with no purpose.

Dmitry K.
  • 972
  • 6
  • 16
  • 4
    C# objects do not have destructors. They *may* have finalizers. Finalizers do not run when objects go out of scope. They run when GC thinks it's time to run them. – GSerg Apr 23 '16 at 21:20
  • 1
    From your link: "The programmer has no control over when the destructor is called because this is determined by the garbage collector" – Poul Bak Apr 23 '16 at 21:25
  • Arguably it is confusing that they use the word 'destructor' to describe a finalizer. Also see http://stackoverflow.com/q/1076965/11683. – GSerg Apr 23 '16 at 21:28
  • @Poul Please indicate to me where I state that the programmer is controlling when the destructor is called? Sounds like you are assuming that the statement "goes out of scope" means the user has some how forced it out of scope. Not what I said. – Dmitry K. Apr 23 '16 at 21:29
  • @GSerg, I wont disagree with you about it being confusing, but the term "destructor" is applicable to C# as its in the the documentation for the language. You can't override the Finalize method, you use a "destructor' to do that. That is the correct terminology. – Dmitry K. Apr 23 '16 at 21:33
  • 2
    One should also note that if the class has a finalizer (a destructor in C# terminology), the garbage collector will not collect this instance immediately, in the next generation-0 collect. Instead it will add the instance to a __finalizer queue__ and will not finish collecting this instance until the next generation-1 collect. So depending on the finalizer (destructor), even if you know it exists and is correctly implemented, can lead to a performance hit. Additionally, as others said, it is best to release those resources now, rather than waiting for possible garbage collections to occur. – Jeppe Stig Nielsen Apr 23 '16 at 23:06
  • @JeppeStigNielsen: I don't quite understand your argument. The finalizer/destructor will exist regardless of whether you depend on it, so isn't there a performance hit either way? – ruakh Apr 24 '16 at 04:07
  • 2
    @ruakh Good question! I think I was assuming that the `Dispose()` method called `GC.SuppressFinalize(this)`. Whenever a destructor exists, that should be the case. In that case a call to `Dispose()` will ensure immediate collection and no finalization queuing. If finalization is not suppressed explicitly like that, you are absolutely right: the performance hit is there either way. People are often surprised that the mere existence of a destructor, _even one with an empty body_, hurts performance. – Jeppe Stig Nielsen Apr 24 '16 at 07:07
  • @JeppeStigNielsen: Ah, I was not familiar with `GC.SuppressFinalize(this)`. It makes much more sense now; thanks! – ruakh Apr 25 '16 at 01:42
1

It is not safe to use disposable objects in this way. Yes, no reference wont be held but the purpose of Disposable pattern is to dispose all unmanaged resources(like OS handles) which cannot be garbage collected.

Yevgeniy.Chernobrivets
  • 3,194
  • 2
  • 12
  • 14
  • 2
    Unmanaged resources will be released during garbage collection if not disposed earlier by an explicit call to `IDisposable.Dispose()`. Of course, this assumes that `IDisposable` is implemented correctly and that the finalizer releases the unmanaged resource. So it is actually "safe" to not dispose a disposable object when it is not longer used and leave it to the garbage collector to clean it up. However, it is not very smart or efficient. – Martin Liversage Apr 23 '16 at 23:04