Disposing Objects

From the client perspective, IDisposable is hidden behind language constructs, too. There are different options to call IDisposable::Dispose. If you have a tracking handle, you can simply use the delete operator. This does not free the object's memory on the GC heap, but it calls IDisposable::Dispose on the object. The next block of code shows how the delete operator can be used:

// deletingObjects.cpp

// compile with "CL /clr:safe deletingObjects.cpp"

using System::Console; using namespace System::IO;

FileStreamA fs = gcnew FileStream("sample.txt", FileMode::Open);

StreamReaderA sr = gcnew StreamReader(fs);

Console::WriteLine(sr->ReadToEnd());

delete sr; // calls Dispose on StreamReader object delete fs; // calls Dispose on FileStream object

Similar to native pointers, you can use the delete operator on a nullptr handle. The C++/CLI compiler emits code that checks if the tracking handle is nullptr before calling IDisposable::Dispose.

Notice that you can use the delete operator on any tracking handle expression. It is not a requirement that the tracking handle is of a type that actually implements IDisposable. If the type of the tracking handle passed does not support IDisposable, it is still possible that the handle refers to an object of a derived type that implements IDisposable. To handle such a situation, the delete operator for tracking handles can check at runtime whether the referred instance can be disposed. Figure 6-3 shows this scenario.

Figure 6-3. Deleting handles of types that do not support IDisposable

If the type of the expression that is passed to the delete operator implements IDisposable, then the compiler will emit code that does not perform an expensive dynamic cast, but a static cast, as Figure 6-4 shows.

ref class SampleClass {

}; ^ SampleClass implements - IDisposable pseudo-code:

IDisposable* disposable;

disposable = static_cast<IDisposableA>(s);

if (disposable != nullptr)

disposable->Dispose();

Figure 6-4. Deleting handles of types that support IDisposable pseudo-code:

IDisposable* disposable;

disposable = static_cast<IDisposableA>(s);

if (disposable != nullptr)

disposable->Dispose();

Figure 6-4. Deleting handles of types that support IDisposable

The static_cast operator used here does not perform a runtime check. Instead, it assumes that the referred object supports the target type (in this case, IDisposable). If this assumption is not true (e.g., because the type of the deleted tracking handle is a type from another assembly and the next version of the assembly does not implement IDisposable anymore), the CLR will throw a System::EntryPointNotFoundException when Dispose is called.

Was this article helpful?

0 0

Post a comment