2

Assuming I have a method public static Rectangle DrawRectangle(Vector origin, Vector size) which returns an object of type Rectangle : IDisposable

If I call only the method DrawRectangle(origin, size), but do not assign the return value to a variable myRectangle = DrawRectangle(origin, size), will the compiler automatically detect this and call DrawRectangle(origin, size).Dispose(), or do I have to do it myself?

Nolonar
  • 5,962
  • 3
  • 36
  • 55

5 Answers5

3

No. Point.

Eventually he finalizer does, but no. It does not automatically CALL Dispose.

TomTom
  • 61,059
  • 10
  • 88
  • 148
  • 1
    I'd also mention that the compiler NEVER disposes the code being compiled, only the CLR. – Erik Philips Jan 07 '13 at 09:28
  • A finalizer *may* call `Dispose`, but it certainly doesn't have to. Disposal and finalization/garbage collection are separate things. – Jon Skeet Jan 07 '13 at 09:30
  • @ErikPhilips meh; I'm not sure that is a useful distinction. And there certainly are places where the compiler *adds* a `Dispose`; `foreach` and `using` being two off the top of my head – Marc Gravell Jan 07 '13 at 09:31
  • 1
    @TomTom the GC just cleans up the memory, calling finalize if there is one; it never does anything specifically relating to `IDisposable` / `Dispose()` - although the finalizer implementation *may* (if it chooses) – Marc Gravell Jan 07 '13 at 09:32
  • lIn some ways, I think the availability of finalizers may do more harm than good, since they often alow code which isn't written properly to "mostly work". Just about he only time finalizers should be important is when doing things like interning immutable objects that implement `IDisposable` (e.g. bitmaps holding pre-rendered pictures), in which case they may be reasonably combined with `WeakReference`. There are a few cases where correct cleanup is annoyingly difficult (e.g. a base-class object creates an `IDisposable`, and then a derived-class constructor throws an exception), but... – supercat Jan 07 '13 at 17:06
  • ...the proper remedy for that problem would be to have language or framework features to better deal with such situations (e.g. provide that if a class implements `IDisposeOnFailedConstruct` and a constructor throws an exception, the framework will call `IDisposeOnFailedConstruct.Dispose` on the partially-constructed instance; that method would of course be expected to deal with the fact that the object wasn't completely constructed). – supercat Jan 07 '13 at 17:10
3

If your Rectangle class implemets IDisposable, try the using( ) { ... } statment when posible.

Msdn link

Luke
  • 22,826
  • 31
  • 110
  • 193
D.Rosado
  • 5,634
  • 3
  • 36
  • 56
2

The compiler builds code in to assemblies and is not responsible for any execution. The .net runtime is what runs your code and more specifically, the garbage collector deals with memory clean up. It is generally best practice to call objects that implement IDisposable inside of a using block. E.g:

using (var obj = new object) { ... do your stuff }

This will help the runtime understand when your object goes out of scope and clean it up earlier, but as long as you dont hold on to a reference to an object, the runtime will eventually clean it up and dispose it for you.

1

If you want the CLR to call the Dispose method, it is usually recommended to implement the so called Dispose pattern in your class. However, I would not rely on CLR and wouldn't wait for GC to collect an object and use the using clause instead.

platon
  • 5,310
  • 1
  • 22
  • 24
1

There are only two scenarios I can think of where the compiler automatically calls dispose; the most obvious would be:

using(var obj = ... )
{
  // some code
}

which is an explicit instruction to say "at the end, whether success or failure, if obj is non-null, call obj.Dispose()". Basically it expands to:

{
   var obj = ...
   try {
       // some code
   } finally {
       if(obj != null) obj.Dispose();   
   }
}

The other is foreach, where-by the iterator is disposed - although it gets a bit complicated, because IEnumerator doesn't specify that IDisposable is required (by contrast, IEnumerator<T> does specify that), and technically IEnumerable is not even required for foreach, but basically:

foreach(var item in sequence) {
   // some code
}

could be expressed as (although the spec may say it slightly differently):

{
    var iter = sequence.GetEnumerator();
    using(iter as IDisposable)
    {
        while(iter.MoveNext())
        {   // note that before C# 5, "item" is declared *outside* the while
            var item = iter.Current;
            // some code
        }
    }
}

In all other cases, disposing resources is your responsibility.

If you don't ensure that Dispose() is called, then nothing will happen until GC eventually collects the object; if there is a finalizer (there doesn't have to be, and usually isn't), the finalizer will be invoked - but that is different to Dispose(). It may (depending on the per-type implementation) end up doing the same thing as Dispose(): but it may not.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • If the collection returns an enumerator of a class type which does not implement `IDisposable` (as opposed to being of type `IEnumerator`), I believe C# will assume that the enumerator instance does not implement `IDisposable`, and will not attempt the cast, even though the actual returned instance could be a derived type which does implement `IDisposable`. – supercat Jan 07 '13 at 16:57
  • @supercat yes, I noted that: see "technically". The equivalents example is meant to be illustrative and semantically-equivalent, not an exact implementation. As doe whether it tries the cast for the subtype scenario: I'd have to look in reflector to comment. In my own IL generator I only disable that if it is sealed/struct, so **cannot** have a subclass. – Marc Gravell Jan 07 '13 at 17:04
  • If `GetEnumerator` returns a type which does implement `IDisposable`, then the compiler will call `Dispose` on it. It's too bad that so far as I know the only name the compiler will look for is `GetEnumerator`, since if it would look for e.g. `GetForEachEnumerator`, it would be possible for that to return a struct which didn't implement any interface (and thus didn't have to implement `IDisposable`), while `GetEnumerator` could return a class which implemented `IEnumerator` and thus had to implement `IDisposable`. – supercat Jan 07 '13 at 17:13
  • @supercat you can use explicit + public implementation to do that, IIRC – Marc Gravell Jan 07 '13 at 19:46
  • One could do that, if one is willing to require consumers of your type who want an `IEnumerator` to either cast to `IEnumerable` first or else call a method named something other than `GetEnumerator`. Neither of those seems particularly attractive. It would seem cleaner to have `GetEnumerator` will return a class object which behaves like a class-type enumerator, while `GetForEachEnumerator` would return a struct whose semantics were different as a consequence of it being a struct, but which would work correctly (and quickly) when used in the exact fashion that `foreach` uses it. – supercat Jan 07 '13 at 20:08