C# Cookbook
Authors: Hilyard J. Teilhet S.
Published year: 2004
Pages: 98-99/424
Buy this book on amazon.com >>


Recipe 3.27. Assuring an Object's Disposal

problem

You require a way to always have the Dispose method of an object called when that object's work is done or it goes out of scope.

Solution

Use the using statement:

using System;
	using System.IO;

	// …

	using(FileStream FS = new FileStream("Test.txt", FileMode.Create))
	{
	    FS.WriteByte((byte)1);
	    FS.WriteByte((byte)2);
	    FS.WriteByte((byte)3);

	    using(StreamWriter SW = new StreamWriter(FS))
	    {
	        SW.WriteLine("some text.");
	    }
	}

Discussion

The using statement is very easy to use and saves you the hassle of writing extra code. If the Solution had not used the using statement, it would look like this:

FileStream FS = new FileStream("Test.txt", FileMode.Create);
	try
	{

	    FS.WriteByte((byte)1);
	    FS.WriteByte((byte)2);
	    FS.WriteByte((byte)3);

	    StreamWriter SW = new StreamWriter(FS);
	    try
	    {
	        SW.WriteLine("some text.");
	    }
	    finally
	    {
	        if (SW != null)
	        {
	            ((IDisposable)SW).Dispose( );
	        }
	    }
	}
	finally
	{
	    if (FS != null)
	    {
	        ((IDisposable)FS).Dispose( );
	    }
	}

Several points to note about the using statement:

  • There is a using directive, such as

    using System.IO;
    

    which should be differentiated from the using statement. This is potentially confusing to developers first getting into this language.

  • The variable(s) defined in the using statement clause must all be of the same type, and they must have an initializer. However, you are allowed multiple using statements in front of a single code block, so this isn't a significant restriction.

  • Any variables defined in the using clause are considered read-only in the body of the using statement. This prevents a developer from inadvertently switching the variable to refer to a different object and causing problems when an attempt is made to dispose of the object that the variable initially referenced.

  • The variable should not be declared outside of the using block and then initialized inside of the using clause.

This last point is described by the following code:

FileStream FS;
	using(FS = new FileStream("Test.txt", FileMode.Create))
	{
	    FS.WriteByte((byte)1);
	    FS.WriteByte((byte)2);
	    FS.WriteByte((byte)3);

	    using(StreamWriter SW = new StreamWriter(FS))
	    {
	        SW.WriteLine("some text.");
	    }
	}

For this example code, you will not have a problem. But consider that the variable FS is usable outside of the using block. Essentially, you could revisit this code and modify it as follows :

FileStream FS;
	using(FS = new FileStream("Test.txt", FileMode.Create))
	{

	    FS.WriteByte((byte)1);
	    FS.WriteByte((byte)2);
	    FS.WriteByte((byte)3);

	    using(StreamWriter SW = new StreamWriter(FS))
	    {
	        SW.WriteLine("some text.");
	    }
	}
	FS.WriteByte((byte)4);

This code compiles but throws an ObjectDisposedException on the last line of this code snippet because the Dispose method has already been called on the FS object. The object has not yet been collected at this point and still remains in memory in the disposed state.

See Also

See Recipes 3.29 and 3.31; see the "IDispose Interface," "Using foreach with Collections," and "Implementing Finalize and Dispose to Clean up Unmanaged Resources" topics in the MSDN documentation.



Recipe 3.28. Releasing a COM Object Through Managed Code

problem

You need to release a COM object from managed code without forcing a garbage collection to occur.

Solution

Use the static ReleaseComObject method of the Marshal class:

int newRefCount = System.Runtime.InteropServices.Marshal.ReleaseComObject(


COMObj


);

where COMObj is a reference to the runtime callable wrapper (RCW) of a COM object.

Discussion

If the COM object is holding on to resources that need to be released in a timely manner, you will want to decrement the reference count on the COM object as soon as possible after you've finished using the COM object and have set it to null . The garbage collector needs to run in order to collect the unreferenced Runtime Callable Wrapper (RCW) around your COM object, thereby decrementing the reference count on the COM object. Unfortunately, there is no guarantee that the garbage collector will run in order to collect the RCW anytime in the near future.

To solve this problem, you could call GC.Collect yourself to try to free the RCW, but this might be overkill. Instead, use the ReleaseComObject method to manually force the RCW to decrement its reference count on the COM object without having to force a collection to occur.

The static ReleaseComObject method returns an int indicating the current reference count contained in the RCW object after this method has finished decrementing its reference count. Remember that this method decrements the reference count contained in the RCW, not the COM object's reference count. When the RCW reference count goes to zero, it releases its COM object.

Care must be used when calling the ReleaseComObject method. Misuse of this method can cause a COM object to be released by the RCW too early. Since the ReleaseComObject method decrements the reference count in the RCW, you should call it no more than one time for every object that contains a pointer to the RCW. Calling it multiple times might cause the RCW to release the COM object earlier than expected. Any attempt to use a reference to an RCW that has had its reference count decremented to zero results in a NullReferenceException exception. The RCW might not have been collected yet, but its reference to the COM object has been terminated .

See Also

See Recipes 3.28 and 3.31; see the "Marshal.ReleaseComObject Method" topic in the MSDN documentation.


C# Cookbook
Authors: Hilyard J. Teilhet S.
Published year: 2004
Pages: 98-99/424
Buy this book on amazon.com >>

Similar books on Amazon