5

In C++, I'm used to using the sentry pattern to ensure that resources acquired are properly released when the block or function exits (see here for example). I used this, for example, for grabbing the graphics state, and then I can do whatever I want to that state, and it gets put back when the sentry object (reference) goes out of scope.

Now I'm using C#, and the same trick doesn't work, because the destructor doesn't get called until who-knows-when later.

Is there some OTHER method that is guaranteed to fire when an object's last reference is released? Or do I just have to remember to call some Restore() or Apply() or DoYourThing() method before returning from any method where I would otherwise use a sentry?

Community
  • 1
  • 1
Joe Strout
  • 2,634
  • 2
  • 28
  • 39
  • 1
    "Is there some OTHER method that is guaranteed to fire when an object's last reference is released" No. :-( I've lamented this too. The .NET Dispose pattern is the best possible substitute. – Moby Disk Sep 24 '14 at 15:17
  • I assume you've seen [Implementing RAII in C#](http://stackoverflow.com/questions/9972763/implementing-raii-in-c-sharp) (maybe even duplicate) – Alexei Levenkov Sep 24 '14 at 15:34

5 Answers5

12

C# has finalizers, like C++, that are called when an object is destroyed. They are in the same form as C++, that is:

~ClassName()
{
}

As you know, though, C# does not have deterministic memory management, and so this isn't really a great guarantee. AS a direct result, you should not use finalizers for releasing unmanaged resources in C#. Instead, we use the IDisposable interface. This exposes a single method on the implementor, Dispose, which is intended to be called when you want to release unmanaged resources.

public class MyDisposable : IDisposable
{
    public void Dispose()
    {
        // get rid of some expensive unmanaged resource like a connection
    }
}

We can also use the using sugar to allow semantic invocation of Dispose() when the using block terminates (gracefully or not).

using(var disposable = new MyDisposable)
{
    // Do something with the disposable
} // Dispose is invoked here

Should you find yourself using finalizers and Dispose, you can consider using the GC.SuppressFinalize method, although that's a bit out of my scope. There was a really good discussion elsewhere on StackOverflow about this here

This can be used to perform RAII-esque trickery, of course, such as

using(var guard = new Guard(resource))
{

}
Community
  • 1
  • 1
Dan
  • 10,282
  • 2
  • 37
  • 64
4

C# provides the using block for this case, which works on any object that implements IDisposable.

For example, if you have a type class Foo : IDisposable then you can do this:

using (new Foo(/* ... */)) {
    // Your code that depends on this resource.
}

This is equivalent to:

Foo x = new Foo(/* ... */);
try {
    // Your code
} finally {
    if (x != null) {
        ((IDisposable)x).Dispose();
    }
}

Except, of course, that you don't have access to x. You can, however, gain such access if you need it by creating a variable in the using block:

using (Foo foo = new Foo(/* ... */)) {
    // Your code that uses "foo"
}

The standard way of creating a class that can be disposed of this way or by the garbage collector is:

class Foo : IDisposable {
    protected virtual void Dispose(bool disposing) {
        // Your cleanup code goes here.
    }

    public void Dispose() {
        GC.SuppressFinalize(this);
        Dispose(true);
    }

    ~Foo() {
        Dispose(false);
    }
}
cdhowie
  • 158,093
  • 24
  • 286
  • 300
  • Thanks, everyone! You all had the right answer (and I feel like a dunce for not thinking of it myself, as I have used "using" elsewhere before). But the pattern @cdhowie shows here is especially good to know about, so I'll mark this as the answer (and upvote everybody else to share the love). – Joe Strout Sep 25 '14 at 13:50
2

To implement deterministic deallocation of unmanaged resources, you would use a Dispose pattern. For many cases you can combine this with a using block if you want this to occur within a specific scope.

File handles or handles to a graphics device would usually be considered a unmanaged resource. These are resources that the .NET framework does not track references for and does not automatically deallocate.

If it is managed resource, just references to C# objects/lists, then usually deterministic deallocation is not necessary, and the garbage collector can usually handle these more efficiently than you can. Don't worry so much about when managed resources are deallocated. If you no longer have a reference to them, then they should be of no concern. The concern comes when you are done with something but somehow have a lingering reference to it that is preventing the GC from deallocating it.

AaronLS
  • 37,329
  • 20
  • 143
  • 202
1

It sounds like what you're describing is objects that implement the IDisposable interface for C#. the IDisposable has a Dispose() method, that when defined properly on your own objects, is used to release resources.

Additionally C# does have destructors defined as such:

public class Foo
{
    public Foo()
    {
        // constructor
    }

    ~Foo() // destructor
}

when wrapping IDisposable objects in a using block, the Dispose() method is automatically called, the other option is to throw it in a finally block (when not using... using)

Kritner
  • 13,557
  • 10
  • 46
  • 72
1

The easiest way to do this is enclosing the sentry object in a using statement. So something like this.

using (sentry = new Sentry())
{
    //do your stuff here
}

After this block, sentry will have been released and out of scope.

reservoirman
  • 119
  • 1
  • 11