6

In C++ I am aware that a virtual destructor should generally be used when one intends to inherit from a base class. However, with C# I am not sure what should be done. Consider the following code:

public abstract class Character
{
    private string characterName;
    public int health;

    Character()
    {

    }

    ~Character(){

    }

    public virtual void SetCharacterName( string tempName )
    {
        characterName = tempName;
    }

    public virtual string GetCharacterName( )
    {
        return characterName;
    }
}

(Note: I have heard that Unity3Ds implementation of C# is slightly different than standard. Perhaps ignore some minor formatting errors, the code is seemingly functional...)

My first instinct was the make the ~Character() destructor virtual, by defining it as:

virtual ~Character(){

}

yet doing so causes the IDE to return an error.

In C#, is it necessary or considered standard to use a virtual destructor for abstract classes which wish to be inherited? Or are there other means of making a virtual destructor with C#?

Dmitry
  • 12,938
  • 5
  • 31
  • 46
TheYokai
  • 311
  • 4
  • 9
  • What error is the IDE returning? – Tim May 09 '14 at 23:11
  • 1
    I hope you know the reasons why C++ has "virtual destructors". It is all about having to manually destroy objects and about pointer types in your C++ code and the problems that spring from it. In C#/.NET you do not manually destroy objects (the garbage collector of the runtime takes care of that, and it also takes care to call the destructors in a inheritance chain in the right order). That means, the very reasons that made virtual destructors necessary in C++ do not exist in .NET -- hence no virtual destructors in .NET. –  May 09 '14 at 23:28
  • @elgonzo - isn't multiple inheritance the main reason for virtual destructors? (without it just automatically calling base one is fine as it is done in C#). – Alexei Levenkov May 09 '14 at 23:46
  • 1
    @AlexeiLevenkov, perhaps it is related to mulitple inheritance, too. But main reason is polymorphism. See here: http://stackoverflow.com/questions/461203/when-to-use-virtual-destructors?answertab=active#tab-top –  May 09 '14 at 23:49
  • To answer Tim's question, in case others are wondering, it said that the Virtual keyword is not allowed before ~Character(). – TheYokai May 10 '14 at 03:31

2 Answers2

11

C# doesn't have deterministic destruction. In fact, it doesn't really have destructors, per se: it has finalizers and IDisposable.

The GC will clean things up if and when it gets around to garbage collecting the object instance. All objects will [eventually] get cleaned up one way or another when the app domain terminates, but it's possible that a given object might hang around for the duration of the app domain. In your case, you don't need to do anything as your object has no resources that need cleaning up. Unreferenced objects will get properly disposed of when the GC sweeps them up.

Mostly, one doesn't need finalizers. You might want to read up on Finalizers at http://msdn.microsoft.com/en-us/library/system.object.finalize.aspx and note that

The exact time when the finalizer executes is undefined. To ensure deterministic release of resources for instances of your class, implement a Close method or provide a IDisposable.Dispose implementation.

You might also want to read Understanding when to use a Finalizer in your .NET class and note:

Why is a Finalize method bad?

...

If an object has a finalizer, it will be placed in the FinalizationQueue and is subject so some additional clean-up. Once the object is no longer referenced on a thread or from a global reference, the next time the Garbage Collector (GC) runs, it will see this object is ready to be collected. But it can’t collect it yet. It has to let the Finalizer run first. So the GC will finish collecting, then the Finalizer will Finalize the object, and then another GC collection will occur.

This can have a huge affect on performance as you should remember that all managed threads will be stopped waiting on the GC and then the GC will be stopped waiting on the Finalizer thread.

There is a lot more data out there about Finalization so I encourage you to read about it as much as possible so that you use it in the best way possible.

If your object needs something deterministic, you can implement IDisposable and either explicitly invoke Dispose() or use a using block:

using ( Character foo = CharacterFactory.CreateInstance("Jane") )
{
   // do something useful with Jane
}

when the enclosing using block is exited, foo.Dispose() is guaranteed to be invoked. It's identical to this code (with the exception of the scope of foo):

Character foo = ... ;
try
{
  ...
}
finally
{
  foo.Dispose() ;
}

However, the point of IDisposable is more about making sure that unmanaged resource are released in a timely manner. DBAs tends to get all grumpy when you block 400 users when your object goes out of scope and is hanging out waiting to be GC'd, leaving an in-flight query running. Or your object goes out of scope, leaving an exclusively locked file open.

Nicholas Carey
  • 60,260
  • 12
  • 84
  • 126
  • 1
    Just nitpicking, but C# has destructors. Look at the current C# 5.0 specification: Chapter 1.6.7.6 is about destructors. I think, in more general .NET lingo it is called "Finalizer" - the C# compiler is turning a destructor into a finalizer. As i said, i am just nitpicking ;) –  May 09 '14 at 23:39
  • 1
    @elgonzo: destructors are *determinitic*; finalizers are not. The CLI spec gets the terminology correct; the C# spec doesn't. [Eric Lippert hypothesizes here](http://blogs.msdn.com/b/ericlippert/archive/2010/01/21/what-s-the-difference-between-a-destructor-and-a-finalizer.aspx) that "the language design committee wished to leave open the possibility that a C# "destructor" could be implemented as something other than a CLR finalizer. That is, the "destructor" was designed to be a C# language concept that did not necessarily map one-to-one with the CLR’s "finalizer" concept." – Nicholas Carey May 09 '14 at 23:47
  • Good to know the semantic differences being associated with these specific terms. And it is an interesting article by Mr. Lippert, thanks for the link :) –  May 10 '14 at 00:06
7

In C#, is it necessary or considered standard to use a virtual destructor for abstract classes which wish to be inherited?

Typically you will not use any destructors in C#. Those may or may not get called by the garbage collector at any time (or not).

When you need deterministic cleanup, implement the IDisposable interface, and use using blocks to clean up (unmanaged resources, for example).

Destructors cannot be inherited or overloaded. Related stackoverflow thread with more details: Inheritance and Destructors in C#

Community
  • 1
  • 1
ChristopheD
  • 100,699
  • 26
  • 154
  • 173