Destructor for Abstract Class
Asked Answered
W

2

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#?

Waylen answered 9/5, 2014 at 23:9 Comment(5)
What error is the IDE returning?Spectroradiometer
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.Periwinkle
@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#).Unpile
@AlexeiLevenkov, perhaps it is related to mulitple inheritance, too. But main reason is polymorphism. See here: #461703Periwinkle
To answer Tim's question, in case others are wondering, it said that the Virtual keyword is not allowed before ~Character().Waylen
E
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.

Eraste answered 9/5, 2014 at 23:37 Comment(3)
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 ;)Periwinkle
@elgonzo: destructors are determinitic; finalizers are not. The CLI spec gets the terminology correct; the C# spec doesn't. Eric Lippert hypothesizes here 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."Eraste
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 :)Periwinkle
F
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#

Flouncing answered 9/5, 2014 at 23:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.