Designing an interface always requires careful considerations of how it will be used. Scott Meyers elegantly catches the entire problem in one sentence in his book Effective C++:
Make interfaces easy to use correctly and hard to use incorrectly.
The people at Microsoft who were in charge for the WCF client code generation either hadn’t read that book or didn’t understand it. They have made an interface that is counter intuitive and hard to use when it comes to disposing of the WCF client.
In my previous post IDisposable and using in C# I wrote that “Always call Dispose on objects implementing IDisposable“. This is true, as long as the class implements IDisposable in a reasonable way. Unfortunately the WCF client doesn’t. The MSDN docs presents the problem.
using(CalculatorClient client =new CalculatorClient()){...}// <-- this line might throw
Console.WriteLine("Hope this code wasn't important, because it might not happen.");
using (CalculatorClient client = new CalculatorClient())
{
...
} // <-- this line might throw
Console.WriteLine(
"Hope this code wasn't important, because it might not happen.");
That is definitely an example of an interface that is hard to use. The hidden call to Dispose might throw with a strange exception which sometimes even hides the real error. There is a simple solution though that makes the above code work as expected.
C# and the .NET environment have automatic memory management through garbage collection. Coming from C++ I think it’s great to not having to worry about memory deallocation. Unfortunately memory from the managed heap (which is where C# objects are placed) is just one kind of resource in a system. There are several other types of resources:
File handles
Network sockets
Database connections
Unmanaged memory
These resources still need to be freed in C#. If the .NET class handling the resource is implemented correctly it will release the unmanaged resource when the object is garbage collected. This is fine as long as it doesn’t matter when the resource is freed. In a program with small memory footprint the garbage collector might never run during the execution of the program, because the low memory usage never triggers a run. In the meantime your program can hold on to an expensive database connection instead of releasing it back to the connection pool for reuse. Eventually the database connection pool is empty and your program (or web site) will start failing.