5

Lets assume we have two class Foo and Bar as given below.

public class Foo
{
    public static Bar BarInstance { get; set; }

    public static void Main()
    {
        AssignBar("A");
        AssignBar("B");
    }

    private static void AssignBar(string name)
    {
        BarInstance = new Bar(name);
    }
}

public class Bar : IDisposable
{
    public Bar(string name)
    {
        Name = name;
    }
    public string Name { get; set; }
    protected virtual void Dispose(bool disposing)
    {
        if (!disposing)
        {
            return;
        }
    }
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

When object A gets replaced by object B. I expect Dispose to called because since there is no reference to Object A exists any more, but it doesn't get called. Could you please explain why?

Should I end up doing CurrentBar.Dispose like below if I want Object A to be disposed.

    private static void AssignBar(string name)
    {
        if (BarInstance != null)
        {
         BarInstance.Dispose();   
        }
        BarInstance = new Bar(name);
    }
Carbine
  • 7,849
  • 4
  • 30
  • 54
  • Thanks for all the answers. I was expecting Dispose to be called immediately once it goes out of scope. But now its clear - it will be called only by Finalizer in a separate thread which is non-deterministic and unreliable. Hence it doesn't happen immediately. Now I am confused which answer to accept :) – Carbine Aug 08 '14 at 08:30

3 Answers3

4

It depends on the ownership.

Is Bar given to Foo with the implication that Foo now owns Bar?

If so, then yes, you should call Dispose on the old before assigning a new instance.

Is Bar given to Foo with the implication that it's more of a loan, ie. you can reference and use this object, but it is owned by something else?

If so, then no, you should not call Dispose on the old before assigning a new instance.


Your code is not altogether clear on this point and I would suggest you clean that up, would make it easier to reason about this type in the future.

The way I see it you have 1 of 3 possible scenarios:

  1. Foo always owns Bar. In this case I would put the disposal of the old instance in the setter of the property, or remove the public setter altogether if the only way to get a new Bar instance into it is through the method you have declared.
  2. Foo never owns Bar. In this case I would not add any code that disposes of the old instance, but then I question the existence of that method. In this case it is likely nobody would really own the newly constructed instance.
  3. Foo only owns Bar instances created through your method, but not instances given to it through the public setter. In this case I would add a new field that tracks whether Foo owns Bar or not, and set this to true in the method, and clear it in the property setter.

Dispose is not special in any way, from the C# standpoint it is just another method, as such there is nothing automatic that will call this method.

However, if the object references unmanaged resources, when the object at some point becomes eligible for collection, its finalizer will be executed releasing those unmanaged resources. However, to deterministically release them when you know they are no longer needed, you need to call Dispose.

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
  • 1
    I would suggest a variation of #3: Have a method which sets `Bar` and includes a parameter indicating whether or not it should accept ownership. Use a flag to keep track of whether or not the object owns the current `Bar`; setting a new `Bar` should dispose the old one if the flag is set, and copy the flag from the passed-in parameter. It may be helpful to also have distinctly-named methods `SetSharedBar` and `SetAndCleanupBar` which chain to the version with the flag, but all the work should IMHO be done within a common method. – supercat Aug 08 '14 at 16:01
3

Dispose is no special method. It will not be called automatically. You'll have to do it.

private static void AssignBar(string name)
{
    if(BarInstance!=null)
    {
        BarInstance.Dispose();
    }
    BarInstance = new Bar(name);
}

I think you are confusing with finalizers and IDisposable. Finalizers are called at the time of garbage collection(not reliable though). If you have implemented DisposablePattern, then you'll have a Dispose(bool) method which is called from finalizer. Where finalizers are called by GC automatially during garbage collection.

Read here for more info

Community
  • 1
  • 1
Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
2

The runtime won't automatically call Dispose for you, it's your responsibility to ensure it's called. Your object will be garbage collected, but this only ensures that memory is reclaimed. It's up to use to release resources.

You can do this using either a using statement:

using(var x = new BarInstance())
{
  // Whatever
}

or you can call it yourself. In your example, since you're replacing the instance you'll need to call Dispose, otherwise you risk a resource leak.

You could opt to use a finalizer in your class, ~Bar. In the finalizer you can dispose of any resources you're holding. However, when the finalizer will be called in non-deterministic, and it's even possible that it will never be called if the garbage collector doesn't kick in.

Sean
  • 60,939
  • 11
  • 97
  • 136