3

I have a class that spawns another UI thread and does it's thing. I need to abort that thread and clean up whenever my parent class is destroyed. So how do I know when my parent class is destoryed?

Coming from C++ my first thought was to put this in the destructor. But C# doesn't really have any destructors - only finalizers and dispose - which from what I understand - may or may not be called (I guess it's a mood thing for the GC??).

That's great and simple - if you may or may not want to release your resources.

But where do you put code that ABSOLUTELY POSITIVELY MUST BE EXECUTED whenever an object is destroyed?

Ryan Kohn
  • 13,079
  • 14
  • 56
  • 81
William Madonna Jr.
  • 242
  • 1
  • 3
  • 12
  • 1
    I don't think C# has this concept. If you want deterministic cleanup, `IDisposable` / `using` is how most people handle it. There is no way to force `.Dispose()` to be called though, just like there is no way to force a client to destroy an object in C++. – recursive Jan 22 '13 at 22:12
  • 1
    Objects in C# do not get destroyed when they go out of scope. So if the question is "executed automatically whenever an object goes out of scope", the answer is "not possible". Otherwise, the finalizer. – Jon Jan 22 '13 at 22:12
  • Note that dispose *is* deterministic. Finalizers may not be called depending on the mood of the GC, but disposal is not an option, and can not be delayed. – recursive Jan 22 '13 at 22:18
  • 2
    You really shouldn't be using multiple UI threads. You're only going to end up in a world of hurt later on, unless you're 100% sure you have no choice. – Servy Jan 22 '13 at 22:19
  • There's a helpful answer on this related question: http://stackoverflow.com/questions/456213/destructor-vs-idisposable – Ryan Kohn Jan 22 '13 at 22:26

4 Answers4

5

You put it in Dispose (implementing the IDisposable interface) and then ensure that Dispose is called when the object is no longer required. There's a language construct that does just this:

using (var foo = new Foo())
{
    // Do something with foo.
}

foo.Dispose will be called at the end of the using block. This is equivalent to:

{
    var foo = new Foo();
    try
    {
        // Do something with foo.
    }
    finally
    {
        foo.Dispose();
    }
}

Note that Dispose is not called automatically when the object leaves scope; you need to do it yourself, using either a using block or by calling it explicitly.

You should, however, provide a finalizer in Foo that calls Dispose, so that if the object isn't disposed before the GC gets to it, you aren't left with unreleased resources:

~Foo()
{
    Dispose();
}

The idea behind the IDisposable pattern is that it tells you unambiguously when a class needs disposing. Here's an article that describes how to implement it properly (accounting for possible descendant classes).

Will Vousden
  • 32,488
  • 9
  • 84
  • 95
  • Yep. The closest C# gets to RAII. It requires you to wrap your the code that uses the resource in `using` blocks, but.... that's how it's done – jalf Jan 22 '13 at 22:15
  • This appears to be the only thing available to me. But this seems like a flaw in the language. Because it depends on the person using this class to know that he MUST use a using{} block. And if he doesn't - bad things happen. I've always thought classes should clean up after themselves without depending on the developer to have to know any details about how to do that for a given class. GC is GREAT for freeing up strings and such - but seems I've found it's achillies heel... – William Madonna Jr. Jan 23 '13 at 00:15
  • @WilliamMadonnaJr. The idea is that if a class implements `IDisposable`, you should **always** call `Dispose` once you're done with it. This interface and the associated pattern tells you that the class holds unmanaged resources that need releasing. Here's an article on how to implement the pattern correctly: http://www.codeproject.com/Articles/15360/Implementing-IDisposable-and-the-Dispose-Pattern-P – Will Vousden Jan 23 '13 at 08:53
3

There is no way to guarentee that something "ABSOLUTELY POSITIVELY [WILL] BE EXECUTED" when an object is destroy (try pulling the plug on your PC --- finalizers ain't gonna be called)

The best you can hope for is the finalizer -- defined in C# using C++ destructor syntax. Although, you be better off implementing IDisposable, and using a using{} block.

James Curran
  • 101,701
  • 37
  • 181
  • 258
  • 1
    True, but not very helpful. :) I think you can safely assume that "ABSOLUTELY POSITIVELY [WILL] BE EXECUTED" means "unless you pull the plug on your PC" ;) – jalf Jan 22 '13 at 22:16
  • LOL! You are right, James - but jalf gets the idea. Obviously - if somebody pulls the plug I'm not too worried about aborting my secondary thread - physics will take care of that problem for me. – William Madonna Jr. Jan 23 '13 at 00:26
  • My point was that is not the only thing that could prevent object destuction from happening, so if you ABSOLUTELY... then you must find some external way of making that guaruntee. If it merely "must be called -- except in special circumstances", then once you enumerate the special circumstance are and are not allowable, you'll probably find the finalizers are fine. – James Curran Jan 24 '13 at 14:19
1

Although it is not common to use this method, you can define a "destructor" in C# by using the ~ character, like so:

class Parent
{
    ~Parent()  // destructor
    {
        // cleanup statements...
    }
}

Note:

The destructor implicitly calls Finalize on the base class of the object.

(source)

Ryan Kohn
  • 13,079
  • 14
  • 56
  • 81
  • 2
    You can, but it doesn't create a destructor in the C++ sense, so it's not very helpful – jalf Jan 22 '13 at 22:14
0

You make your class a Component and the containing class a Container.

See: C# - What is a component and how is it typically used?

Other answers seem to be busy with "going out of scope" use case. But "whenever my parent class is destroyed"? If "parent class" is a "containing object", components are the right tool.

Community
  • 1
  • 1
Anton Kovalenko
  • 20,999
  • 2
  • 37
  • 69