Implementing IDisposable and the Dispose Pattern Properly

Explains how to properly implement the IDisposable interface, the Dispose Pattern, and deterministic finalization.

Introduction

In most modern programming languages, memory is allocated on the heap or the stack. Memory allocated on the stack stores local variables, parameters, return values, and is generally managed by the operating system. Memory allocated on the heap is handled differently by different programming languages. In C and C++, memory must be managed manually, while in C# and Java, memory is managed automatically.

Even though manual memory management is easier for the language runtime, it adds complexity for the programmer, which can lead to bugs and coding errors due to improper memory management and object lifecycle maintenance.

Automatic memory management is known as garbage collection. Even though garbage collection is harder for the language runtime, it reduces the complexity for the programmer, and helps reduce the number of bugs and coding errors caused by manual memory management.

Garbage Collection in .NET

The garbage collector (GC) in .NET is a core part of the .NET Common Language Runtime (CLR) and is available to all .NET programming languages. The GC was never meant to manage resources; it was designed to manage memory allocation, and it does an excellent job at managing memory allocated directly to native .NET objects. It was not designed to deal with unmanaged memory and operating system allocated memory, so it becomes the responsibility of the developer to manage these resources.

In non-garbage collected languages, as soon as the object's lifetime ends, either through the completion of the local block of execution or when an exception is thrown, the destructor kicks in and the resources are automatically released. While garbage collection simplifies the management of the object lifecycle, it does prevent an object from knowing when it will be collected, which means that it is difficult to ensure that the resources held by that object are released early. Before the memory associated with an object is reclaimed by the GC, the Finalize method (if it is present) is invoked. This method is not tied to the lifetime of the object, so the timing of when (or even if) Finalize is called is undefined. This is what is meant by saying that the GC performs non-deterministic finalization.

The lack of deterministic finalization is a common complaint about garbage collected languages. The primary goal when dealing with unmanaged resources is to make use of them in the most efficient manner. Lacking deterministic finalization would seem to violate that goal. The problem with non-deterministic finalization is that it happens at an undetermined point in the future, usually when certain memory-exhaustion thresholds are met. If the object holds on to expensive resources, such as file handles or database connections, those resources are only released when the object is finalized. Finalization is the "safety net" provided by the CLR to help ensure that objects are cleaned up if something goes wrong (either the program crashes, or through coding omissions).

Fortunately, the .NET Framework provides many abstractions to hide the complexity of dealing with unmanaged resources. In fact, many of the CLR classes make use of these unmanaged resources on your behalf and handle all of the resource management transparently.

The CLR does provide a way to implement deterministic finalization through the IDisposable interface, a Dispose method for explicit cleanup, and in some cases, a Finalize method for implicit cleanup. This is commonly referred to as the Dispose Pattern (or the IDisposable Pattern).

Implementing this pattern correctly is critical to ensuring the proper, timely cleanup of resources, and also provides users with a deterministic, familiar way of disposing those resources.

IDisposable and Resource Cleanup

The IDisposable interface is defined as:

publicinterface IDisposable
{
void Dispose();
}

In order to use the IDisposable interface, you would declare a class like this:

Explicit Cleanup

In every case where a type owns resources, or owns types that own resources, you should give users the ability to explicitly release those resources by providing a public Dispose method. This alleviates some of the reliance on the GC, and provides users a way to deterministically reclaim resources.

Implicit Cleanup

Implicit cleanup in .NET 2.0 should be provided whenever possible by protecting resources with a SafeHandle. In .NET 1.0 or 1.1, this class does not exist, so you will need to implement a finalizer. In .NET 2.0, thanks to the SafeHandle class, implementing finalizers is rarely needed. If additional finalization is needed (or you are working with .NET 1.0 or 1.1), you can implement the protected Finalize method using the language specific syntax. The runtime will call Finalize for you non-deterministically as part of the GC's finalization process, providing a last chance for your object to release resources at the end of its lifetime.

You really don't want to write a finalizer if you don't have to. Writing them properly can be very difficult, and by writing one, it makes your class more expensive to use, even if the finalizer is never called. All objects that implement a finalizer must be put on a list of finalizable objects (called the finalization queue) maintained by the GC. This is handled automatically, but it can't be avoided. When you must cleanup resources, you almost always want to provide it in a Dispose method, not in a finalizer. However, when you do need a finalizer, you want it in addition to, not instead of, Dispose.

Syntax Note and Framework Version Difference

The Dispose and Finalize methods serve very different purposes, and have different language syntax for declaring them.

Language

Destructor Syntax

Finalizer Syntax

C#

public void Dispose()

~T()

C++ (.NET 2.0)

~T()

!T()

C++ (.NET 1.0/1.1)

public void Dispose()

~T()

Visual Basic (.NET)

Public Sub Dispose() Implements IDisposable.Dispose

Protected Overrides Sub Finalize()

The Dispose Pattern

The Dispose Pattern is defined by the IDisposable interface.

If your class is sealed (NotInheritable in Visual Basic), then you don't need to follow the Dispose Pattern; you should implement the Dispose and Finalize methods using simple methods. You do still need to follow the rules regarding how to implement Dispose and Finalize, you just don't need to implement the full pattern.

For classes that aren't sealed and need to do resource cleanup, you should follow the Dispose Pattern exactly. The pattern has been designed to ensure reliable, predictable cleanup, to prevent temporary resource leaks, and to provide a standard, unambiguous pattern for disposable classes. It also aids subclasses to correctly release base class resources.

Syntax Note

If you are using C++ (.NET 2.0), you can simply write the usual destructor (~T()) and the compiler will automatically generate all of the code to implement the Dispose Pattern. If you need to write a finalizer (!T()), you should share the code by putting as much of the work into the finalizer as it is able to handle (the finalizer can't access other objects, so don't put code there that needs them), put the rest in the destructor, and have the destructor explicitly call the finalizer.

The Dispose Pattern should be implemented on classes with disposable subtypes, even if the base type does not own any resources. This helps programmers who are using your base class to dispose off further derived instances properly. If you are inheriting from a class that already implements IDisposable, don't re-implement it. You only need to implement IDisposable if a class in your inheritance chain doesn't already implement it.

A great example of this is the System.IO.Stream class. Even though it is abstract and doesn't hold any resources, its subclasses do. As a result, it implements the Dispose Pattern to aid the subclasses.

The public void Dispose() method should be left final (in other words, don't make this a virtual method), and should always look like this:

publicvoid Dispose()
{
Dispose(true);
GC.SupressFinalize(this);
}

The order of the two calls is important, and shouldn't be changed. This order ensures that GC.SupressFinalize() only gets called if the Dispose operation completes successfully. When Dispose calls Dispose(true), the call may fail, but when Finalize is called later, it calls Dispose(false). In reality, these are two different calls which can execute different portions of the code, so even though Dispose(true) fails, Dispose(false) may not.

All of your resource cleanup should be contained in the Dispose(bool disposing) method. If necessary, you should protect the cleanup by testing the disposing parameter. This should happen for both managed and unmanaged resources. The Dispose(bool disposing) runs in two distinct scenarios:

If disposing equals true, the method has been called directly or indirectly by a user's code. Managed and unmanaged resources can be disposed.

If disposing equals false, the method has been called by the runtime from inside the finalizer, and you should not reference other objects. Only unmanaged resources can be disposed.

To give your base classes a chance to cleanup resources, you should always make a call to your base class' Dispose(bool disposing) (if it is available) as the last operation in your own Dispose(bool disposing) method. Make sure to pass the same value for disposing to the base class' Dispose(bool disposing) method.

protectedvirtualvoid Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// Dispose managed resources.
}
// There are no unmanaged resources to release, but// if we add them, they need to be released here.
}
disposed = true;
// If it is available, make the call to the// base class's Dispose(Boolean) methodbase.Dispose(disposing);
}

If your object is responsible for at least one resource that does not have its own finalizer, you should implement a finalizer in your object. If your base class already overrides Finalize to follow this pattern, you shouldn't override it yourself. Your Finalize method should make a single virtual call to Dispose(false). All of the finalization cleanup logic should be in the Dispose(bool disposing) method.

If any of the base classes in your inheritance chain implements the IDisposable interface, overrides void Dispose(), or overrides Finalize, you should simply override Dispose(bool disposing), adding your cleanup logic and making sure to call base.Dispose(disposing) as the last statement.

Syntax Note

Dispose should be considered a reserved word in order to help prevent confusion, so you shouldn't create any other variations other than:

void Dispose()

void Dispose(bool disposing)

Some Examples

The simplest implementation of the Dispose Pattern does not include a Finalize method. This is the pattern that you will follow for the majority of types.

A more complex implementation of the pattern is a base-class implementation that implements a Finalizer. The ComplexCleanupExtender shows how you would hook into the Dispose and Finalize cycle from a subclass. Notice that it does not re-implement Dispose or Finalize.

Implementing Dispose

If your class has a finalizer, you should always implement Dispose. This gives users of your class the ability to explicitly clean up the resources which the finalizer is responsible for. You can also implement Dispose on classes that don't have finalizers. The only exception to this rule is for value types, which can't have either a finalizer or a destructor.

It is important to remember that Dispose may be called more than once. If that happens, you should never throw an exception, but you may choose to ignore the subsequent calls.

Language Caution

The C# automatically generated finalizer chaining does call Dispose(bool) multiple times, which is why it is especially important to implement the pattern only once in the inheritance chain.

If your object controls any disposable types, it should call Dispose on those types in your own Dispose method. If this is done from inside the Dispose(bool disposing) method, you should only do this if disposing is true. If your object doesn't control a disposable type, you shouldn't attempt to dispose off it as other code could still be referencing it.

In C++, you can follow the normal pattern of storing the TextReader by value. The destructor will automatically call reader.~TextReader() following the normal C++ semantics.

You should not throw exceptions from within Dispose except under critical situations. If executing a Dispose(bool disposing) method, never throw an exception if disposing is false; doing so will terminate the process if executing inside a finalizer context.

Recreating an object that has already been disposed is usually very difficult, and generally should not be done. Because of this, you should consider making your object unusable after calling Dispose by throwing an ObjectDisposedException. If you are able to reconstruct the object, you should warn users that they must potentially re-dispose of an object multiple times.

If the semantics of your object allows for it, implement a Close method for your resource cleanup. This method implementation should be identical to Dispose as most developers will not think to call both Close and Dispose. In these cases, the Dispose method should be a call to Close.

There are times, however, when it is necessary to provide different implementations for Close and Dispose. This is usually the case when an object can be opened and closed multiple times without recreating the instance. The .NET Framework uses this pattern with the System.Data.SqlClient.SqlConnection class. This class allows you to open and close a connection multiple times, but the instance still needs to be disposed after you are done using it.

Advanced Implementation

As an alternative, you can release the resources in Close and lazily reacquire them later in a subsequent Open. If you choose to do this, you should call GC.ReRegisterForFinalize(this) when reacquiring them. You will also potentially need to reconstruct the object state.

If you have cyclic references in your objects, you should set those references to null before calling Dispose.

In this example, given an instance of CyclicClassA a and CyclicClassB b, if a.cycle = b and b.cycle = a, transitive disposal would ordinarily cause an infinite loop. In the above example, notice that the object’s state is nulled out first to prevent such a cyclic loop from happening.

You should also consider setting any large and expensive managed objects that you own to null before calling Dispose. This is seldom necessary, but it can help reduce the lifetime of the object by making it eligible for garbage collection sooner. Of course, the definition of large and expensive is subjective, and should be based on performance profiling and measurement.

If you are creating a value type, you should avoid making it disposable, and it should never contain unmanaged resources directly.

Implementing Finalize

Finalizers are very difficult to implement correctly, mainly because you cannot make certain (normally valid) assumptions about the state of the system during their execution. If you decide to implement a finalizer, you should make sure to do it properly. There is both a performance and code complexity cost associated when implementing a finalizer, so consider it very carefully before you do so. When possible, you should use resource wrappers, such as SafeHandle, to encapsulate unmanaged resources.

Finalization increases the cost and duration of your object's lifetime since each finalizable object must be placed on the finalization queue when it is allocated. This happens even if the finalizer is never called. This has the side effect of making the GC work harder to dispose of your object, and causes it to be kept alive longer.

If you must implement a finalizer, make the Finalize method protected, not public or private. For C# and C++, the compiler will do this automatically for you.

These rules do not apply just to the Finalize method, but to any code that executes during finalization. If you implement the Dispose Pattern described in this article, it also applies to the code that executes inside Dispose(bool disposing) when disposing is false.

Since finalizers run non-deterministically, there is no ordering among them, so you can't rely on them being executing in a specific order. You should not access any finalizable objects your type may have a reference to, because they may have already been finalized. As a result, you should only free unmanaged resources that your object owns.

Implementation Caution

This caution also extends to static variables. Accessing a static variable that refers to a finalizable object is not safe. This also applies to calling a static method that may use values stored in static variables. In .NET 1.1 and later, you can use Environment.HasShutdownStarted to detect if your finalizer is running. It is okay to access unboxed value types.

You should never directly call the Finalize method. In C#, this is not allowed, but it is possible in VB and C++. In fact, it is legal Intermediate Language (IL) syntax. Even though you should never directly call Finalize, it should still be able to handle situations in which it is called more than once. In order to do this, you may need a way to detect that finalization has already occurred.

It is always possible that other objects in the finalization queue might still have live references to your object, potentially even after your finalizer has run. You should be able to detect when your object is in an inconsistent state during the execution of any method. If you define a finalizer that closes a resource used by your type, you may need to call GC.KeepAlive at the end of any instance method that doesn't use the this pointer (Me in Visual Basic) after doing some operation on that resource. This also implies that you need to be able to handle partially constructed instances, which can happen when the constructor never completes. If the constructor throws an exception, Finalize will still be called. In this instance, it is possible that some of the fields have not been initialized.

For example, in the following code, list may be null if the constructor throws an exception before list is assigned to.

Finalizers should not raise any unhandled exceptions, except in very system critical conditions, such as OutOfMemory. As of .NET 2.0, throwing an unhandled exception will terminate the entire process.

Finalizers should be simple enough so they don't fail. Since memory allocations may fail due to a lack of memory (we are, after all, running in the context of the GC), you should never allocate memory from within a finalizer. This is especially important in a critical finalizer or from SafeHandle's ReleaseHandle method. Critical finalizers are restricted to only calling a reliable subset of the Framework. If your critical finalizer detects corruption, or gets a bad error code from the Win32 subsystem, throwing an exception may be a reasonable way of reporting this error, though for SafeHandle's ReleaseHandle, you should return false.

In some very rare circumstances, only critical finalizers will be run. In even rarer circumstances, no finalizers will be run. You should never assume that your finalizer will always run. A good way to handle this is to wrap critical resources in a non-public instance that has a finalizer. This way, anyone that uses your type won't be able to suppress finalization. If you can migrate to using SafeHandle and never expose it outside your class, you can guarantee finalization of your resources.

If you need a finalizer that absolutely must execute, consider using a critical finalizable object. SafeHandle is one such object. Any class that inherits from CriticalFinalizerObject is also safe.

Except in very controlled designs, such as the Dispose(bool disposing) method, you should not call virtual members from within your finalizer. The most derived implementation of the virtual method will be run, and there is no guarantee that it will chain to its base class as it should.

Finalizers can be run in any order, on any thread, can occur on multiple objects simultaneously, and even on the same object simultaneously. In general, there are no guarantees that the threading policy for finalization will stay the same in the future, so you should not depend on how it is implemented today. Your finalizer should be able to run on any thread; that is, it should be thread-safe and thread agnostic.

Advanced Information

For a full description of the threading environment for finalization, you can see the blog entry by Chris Brumme at MSDN[^].

In addition to being thread agnostic and thread safe, your finalizer should avoid making any blocking calls. You should not perform any synchronization or lock acquisition, sleep the thread, or any other similar operations, unless there is a real security or stress bug that would cause finalization to fail. Blocking execution in the finalizer could delay or even prevent other finalizers in the queue from running. If you have to execute atomic thread-safe operations, you should use the Interlocked class since it is lightweight and non-blocking.

It is important to remember not to modify the thread context from within your finalizer, as it will end up polluting the finalizer thread. The finalizer will run an entirely separate thread than the one your object was on when it was alive, so don't leave the finalizer thread impersonated, access thread local storage, or change the thread's culture.

If you need to recycle (resurrect) the object, you should try to do it in your Dispose method. Only do this in the finalizer as a last resort. Re-registering an object has performance implications, and can cause unexpected behavior. In addition, you should never assume that by avoiding resurrecting your object, you have prevented it from being accessed after (or during) finalization. It is possible that other objects could attempt to use your objects as if you were still alive. The best option is to throw an exception in these situations, treating it as a similar situation to accessing an already disposed object.

Value types should not have a finalizer. Only reference types get finalized by the runtime.

Syntax Note

For C# developers, the C# destructor syntax is automatically converted to a Finalize() method by the compiler. If you implement the C# destructor syntax, be sure not to include a call to base.Finalize() since it will be included for you.

If you try to define both a destructor and a Finalize() method, or you try to explicitly call your base class' Finalize() method, the compiler will generate an error. The compiler will automatically determine the presence of destructors in a class hierarchy and call every destructor in the proper order (from the lowest subclass to the topmost base class).

Using Disposable Objects

Implementing IDisposable and the Dispose Pattern are very important for how you write a class, but do not dictate how you use an instance of the class. Unfortunately, there is no way to force the users of your class to call Dispose when they are done using it, or to force them to use proper exception handling to make sure that Dispose is called even when an exception is thrown.

If the object you are using implements IDisposable, or even just implements a public Dispose method, the client should properly scope the code and then dispose of the resources it holds in a try/finally block. Without the try/finally block, the client's call to Dispose will never be reached if the calling methods cause an exception to be thrown. You should never ignore exceptions that are thrown from a Dispose call.

The using Statement

The C# and VB languages provide the using statement to make it easier for developers to work with disposable objects by automatically disposing of them when control leaves that scope. C++ provides this through the stack allocation semantics.

Interfaces and the using Statement

As we have seen, the using statement generates a type-safe implicit cast to IDisposable. Unfortunately, this prevents the using statement from being used with interfaces, even if the implementing type supports IDisposable.

One possible workaround for this is to make ISomeInterface derive from IDisposable instead of MyClass. This may not be possible in all cases, and may not be desirable, depending on where ISomeInterface is defined and what its purpose is.

A Complete Example

Here is a complete (and slightly more complex) example that implements the Dispose Pattern in C#.

Conclusion

As you can see, there are a lot of details involved in properly implementing IDisposable and the Dispose Pattern. However, by following the proper template and rules, you can ensure that your disposable objects are handled correctly and behave as first-class citizens in the garbage collection process.

I've been involved with computers in one way or another for as long as I can remember, but started professionally in 1993. Although my primary focus right now is commercial software applications, I prefer building infrastructure components, reusable shared libraries and helping companies define, develop and automate process and code standards and guidelines.

What's the difference compared to add a new public method, do the stuff inside to release open resources (ex : close any open COM port) then tell users to call this public method at the end of the world ?

Does the added value of all this just to provide a public method with a given naming convention ?

Doing otherwise would make about as much sense as implementing IDisposable on a class with no disposable objects!

"MyClass" itself will get cleaned up properly with no extra effort on your part.

"SomeDisposableObject" will of course implement the full IDisposable pattern, and it will be cleaned up properly when Dispose is called.

Quote:

IDisposable:

The primary use of this interface is to release unmanaged resources.

The garbage collector automatically releases the memory allocated to a managed object when that object is no longer used. -MSDN

Which is exactly what I just said. ("MyClass" is a managed object.)

As for code clarity, etc, I never look further than intellisense to determine whether or not I need to call Dispose() on a class. (I've certainly never looked into a classes implementation to make this determination, and even if I did, I would imagine that the Dispose() method would be a dead give away.)

Personally, I think you're slowing your code down, with little to no benefits, and possibly causing problems by adding objects to the dispose list that shouldn't be there. (ie, managed objects aren't supposed to be handled like this.)

Imagine disposing of 20,000 2D sprites after using them, not only are you asking the GC to take care of the unmanaged resources, but, the managed classes themselves as well.

In the simplest class hierarchy case, you have just doubled the amount of stuff the GC is being asked to take care of. (ie, 20,000 sprite classes, and 20,000 textures, etc,.)

Then, people wonder why the GC chokes, and their C# based games, and applications stutter during garbage collection...

That depends on which MyClass declaration you're referring to. If you're talking about the ones shown in the "Implementing Finalize" section, you're right. However, you can have a finalizable class that doesn't implement IDisposable, however if you're going to implement a finalizer the class should also implement IDisposable. (I should update the article to make that more clear.)

pi3k14 wrote:

using is a nice indication that you have a resource "craving" class.

I don't think you can make a blanket statement like that. Yes, if the class implements IDisposable, it's doing so for a reason and is most likely holding on to a resource that needs to be released. That may not mean it's a "resource craving class", it could simply mean that the class is working with an unmanaged resource that is scarce or precious to the operating system and wants to "play nice" and ensure that the resource is released as soon as possible so other applications can access the resource.

pi3k14 wrote:

We have found in our projects that active disposing of objects is a necessity
for not running out of memory (50,000+ objects that is a bit more than a
sprite)

Yes, that's not surprising. Again, if the objects you're using implement IDisposable they're (hopefully) doing so for a good reason and you shouldn't ignore that fact.

pi3k14 wrote:

GC have to take care of your objects regardless of you calling Dispose or not,
calling Dispose helps the GC, it doesn't burden the GC with more work.

I never said that calling Dispose burdens the GC with more work. Calling GC.Collect isn't usually a good idea, but you should always call Dispose when you're done using the instance. Yes, the GC has to "take care of your objects" whether Dispose has been called or not. Calling Dispose helps the GC but, more importantly, it should release any unmanaged memory that the class was using. The GC doesn't know anything about how unmanaged resources are being allocated in your code. Effectively, all it knows is that the class implements IDisposable. It's up to the calling code to recognize that the class is disposable and do the right thing by calling Dispose when it's done using an instance of the object.

Scott Dorman

Microsoft® MVP - Visual C# | MCPD
http://about.me/scottdorman

[Blog][Articles][Forum Guidelines]Hey, hey, hey. Don't be mean. We don't have to be mean because, remember, no matter where you go, there you are. - Buckaroo Banzai

Hello! What should I do if I have a class which has a disposable member, but this member is coming from outside of the class through the constructor? Should I implement IDisposable in this case and set the variable to null?

It depends. If the member lifetime is to be aligned with your class, you need to dispose both when disposing (in Dispose(disposing) ) is set to true. If the member object should continue to be used outside the scope of your class, then you do not dispose it.

Example: You have a WindowsForms User Control. Each child control you add to it is a disposable object. When disposing the control, you should dispose all child controls it may have (like buttons, text boxes and etc). However, if the control references the main application Form (as a field or property), disposing the form from the user control will close the application. Thus, you should not dispose the main form when disposing that control, even if it is a property of the control. Instead, simply dereference the form by setting it to null. If somehow the form is never disposed by calling Dispose and you properly dereference it, then the Garbage Collector will do its job

You also need to unregister any event handlers to the objects (the form and it's child controls). Event handlers are treated as roots even if the object is set to null. I've fixed many memory leaks where handlers were not unregistered.

Dave is correct. When for example, you dispose of a user control that references the main form, and you need not destroy the main form with the control's disposal, you should un-register any event hooks between your control and the form. Failing to do so will keep your user control in memory, and even worse, it will still try to respond to event invocations (which will have unknown consequences).

Nice article, really has helped me on several issues I encountered.
But I'm still stuck on 2 points at the moment. I have a class that wraps the UdpClient from the Sockets.Net namespace, and I'm not sure where to put my cleanup parts for the event handlers and the UdpClient itself.

Your class has no unmanaged resources; m_socket is a managed resource. Consider that if your class becomes eligible for garbage-collection and m_socket isn't used anywhere else, m_socket will itself be eligible for garbage collection and will take care of closing itself.

The Dispose pattern made some sense before the advent of the SafeHandle class in .Net 2.0, but today it's almost never appropriate for one class to handle both managed and unmanaged resources. Instead, any unmanaged resources should be stuck in wrapper classes like SafeHandle, thus turning them into a managed resources. In nearly every case, calling Dispose(False) should do nothing.

In this case setting the handle to null isn't strictly necessary. The only time it becomes important is if the object is "large" (>64K) in size. I have a feeling that the reason you are encountering a null reference exception when you try to access the handle after you call dispose is that your accessor isn't taking in to account if the object has been disposed. You should probably have a property that looks something like this:

100+ lines of code just to close some file handle ... refutes the fundamental objective of C# as a concise and practical language.

I think you are missing the point. The point of the interface and pattern isn't just to "close a file handle", it's to ensure that unmanaged (native) resources are cleaned up. The fact of the matter is that the GC doesn't have any knowledge (nor should it) of how to clean up those unmanaged resources and it relies on the fact that the object using those resources knows how to perform the cleanup at the right time.

I don't think this retutes the idea that C# is a concise and practical language at all.

bronislav wrote:

BTW if you look into .NET source code released by Microsoft, and search for "override void Dispose()", you will find plenty of entries.

I did just search the 2.0 release of the CLI for that string and didn't find any entries, so I'm not sure what version of the Framework you are looking at when you are making this statement.

As far as "your take" the biggest problem here is that by implementing a finalizer you are always adding your object to the finalization queue when there is no real need for the finalizer. By doing this, your object will always last one extra GC cycle. Beyond that, it doesn't follow the pattern and can potentially cause problems later on in further derived classes.

I know it's a C# article, but since you also mention C++,
I would have liked to see more about the difference between
using C++ finalizers and Finalize in other .NET languages.
Also, the use of the delete operator for deterministic finalization
when not using stack-based semantics. Just 2 cents from a C++ guy...

know it's a C# article, but since you also mention C++,
I would have liked to see more about the difference between
using C++ finalizers and Finalize in other .NET languages.
Also, the use of the delete operator for deterministic finalization
when not using stack-based semantics. Just 2 cents from a C++ guy...

I'll see if I can find any information and update the article. No promises on time frame, however.