views:

34

answers:

4

Let's say I have a class with a object field. When Dispose() is called I would like to clear the reference to that object. The private field can only be set once, so ideally I would like it to be readonly, but if it is readonly there is a compile time error when I try to release the reference to the object during Dispose(). Ideally I would like to have a safe dispose AND mark the _value field as readonly. Is this possible or even necessary?

public class Foo : IDisposable
{
      public Foo(object value)
      {
            _value = value;
      }

      public object Value { get { return _value; } }
      private readonly object _value;

      public void Dispose()
      {
            //Cleanup here
            _value = null     // causes compile time error
      }
}
+3  A: 

That's not necessary, even if it were possible. Dispose is intended to clean up unmanaged resources. When you're dealing with managed objects, the garbage collector will take care of that indeterminantly once the objects are unreferenced. Under normal circumstances, you do not need to take action to force the collector to do its job. Just write your code with objects in properly limited scope and you will be fine.

Anthony Pegram
There are many circumstances where disposed is appropriate and essential even for objects which have no unmanaged components. Any object which receives events from longer-lived object must unsubscribe all its events (typically done from Dispose) in order to avoid being kept alive by the long-lived object.
supercat
A: 

That's true because you can not assign a value to readonly filed except in constructor or in variable initilizer.

Since this property is instance level and this is not an unmanaged resource so you don't need to worry about as soon as your instance goes out of scope , GC will collect it any time.

saurabh
+1  A: 

That is not necessary nor correct. Wanting to do what you ask in your question seems to indicate you are somewhere accessing a disposed object, and that is wrong.

Rather than try to do what you have asked, you should perhaps implement IsDisposed (which btw is part of the standard Dispose pattern) and check it first.

As others have noted, the Dispose pattern is intended for releasing unmanaged resources.

Mitch Wheat
+1  A: 

Setting the reference to null does not in fact do anything. The garbage collector will clean up the object when there are no longer any references to it, which in this case since you are doing this in the Dispose method presumably the instance of Foo is about to no longer have any references to it and the difference in timing is probably not meaningful. Typically you implement the Dispose pattern because your type has as a member a class that itself implements IDisposable (in this case the type is Object, which does not implement IDisposable), or you have unmanaged resources that you would like to release deterministically. You can find a description of the Dispose pattern here. Note that if you create a readonly member variable of a type that implements IDisposable you can call the Dispose method on that object inside your Dispose method:

public class SomeClass : IDisposable
{
    private Boolean mDisposed;
    private readonly MemoryStream mStream = new MemoryStream(); // Could be any class that implements IDisposable
    public void Dispose() {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    protected void Dispose(Boolean disposing) {
        if (disposing & !mDisposed) {
            mStream.Dispose();  // Could and should call Dispose
            mDisposed = true;
        }
        return;
    }
}

This works because the readonly nature is on the reference to the object, not the object itself.

Steve Ellinger
Hi,does GC.SuppressFinalize(this); has any effect ?As my understanding, GC will not keep reference of SomeClass to Finalization queue as there is no Finalizer defined.
Int3
Follow the link for the dispose pattern in my answer; calling GC.SuppressFinalize is part of the pattern. In this instance it may not have any effect, but it is a good habit to get into because if the GC calling the Finalize method has performance implications.
Steve Ellinger