IDisposable and Marshal.ReleaseCOMObject and dynamic in C#
If you have worked with COM, you know that for every COM object that you access is not only necessary to null the reference, but also call Marshall.ReleaseCOMObject .
This is a very error prone task, because you have all try / finally blocks
// declare a, ws, w try{ a=new Application(); ws = a.Workbooks; w = ws.Add(); //code } catch(...) { if( w != null){ Marshal.ReleaseComObject(w); w = null; } if(ws !=null){ Marshal.ReleaseComObject(ws); ws = null; } if( a!= null) { Marshal.ReleaseComObject(a); a= null; } }
All of this could be done easy with IDisposable, if
1. IDisposable calls the Marshal.ReleaseCOMObject
2. Find a way to call methods / properties on the COM object from the class that implements IDisposable
I have done this and the result is like this:
using (dynamic a = new ComDisposable(new Application())) { using (dynamic ws = a.Workbooks) { using (dynamic w = ws.Add()) { using (var shs = w.Sheets) { using (var s = shs[1]) { //Worksheet a; using (var r = a.Range("A1")) { r.Value2 = "http://ignatandrei.github.io/ToolsAndUtilities/";; using (var f = r.Font) { f.Bold = true; } } } } w.SaveAs(fileName); w.Close(); } } a.Quit(); }
Video at https://youtu.be/2qbAcSjL1gU
NuGet package at https://www.nuget.org/packages/ReleaseComObjectDisposable/
There is a lot of false information and confusion about using Marshal.ReleaseComObject(). In general it is not needed, and it is safer to replace it with an explicit GC.Collect() call.
It is never necessary to call Marshal.ReleaseComObject(…) or Marshal.FinalReleaseComObject(…) when doing Excel interop. It is a confusing anti-pattern, but any information about this, including from Microsoft, that indicates you have to manually release COM references from .NET is incorrect. The fact is that the .NET runtime and garbage collector correctly keep track of and clean up COM references.
If you want to ensure that the COM references to an out-of-process COM object is cleaned up when your process ends (so that the Excel process will close), you just need to ensure that the Garbage Collector runs. You do this correctly with calls to GC.Collect() and GC.WaitForPendingFinalizers(). Calling twice is safe, end ensures that cycles are definitely cleaned up too.
One source of confusion happens when running under the debugger: local references will be artificially kept alive until the end of the method (so that local variable inspection works). So GC.Collect() calls are not effective for cleaning object from the same method (under the debugger). It’s better to split the code doing the COM interop from the GC cleanup into separate methods.
You can see some code samples to try yourself, in my answer here: http://stackoverflow.com/questions/32572836/create-reusable-excel-styles-for-c-sharp-interop-objects
So you say that is better to force Garbage Collector rather than to dispose property the objects?
Also, from MSDN it says(Forcing a Garbage Collection) https://msdn.microsoft.com/en-us/library/s5zscb2d(v=vs.85).aspx
“Before the garbage collector performs a collection, it suspends all currently executing threads. This can become a performance issue if you call GC.Collect more often than is necessary” – mostly in ASP.NET application.
Calling GC.Collect() and WaitForPedningFinalizers is a bad idea for two reasons.
1) There is no guarantee GC will run finalizer on the RCW.
2) GC is very expensive, so by calling it you are creating potential huge performance problem.
Calling ReleaseCOMObject is a bad idea in general since only one RCW is created for a COM object instance, no matter how many times managed client gets the same instance. So by forcefully clearing refcount in RCW you unknowingly invalidate the object any other managed code in the same appdomain may currently have reference to and use.
As described in MSDN article you linked to, you should use the API only in very special cases, like when you have no choice but have to control disposal order, or if you actually have to do disposal “in timely manner”. But even in these extreme cases you have to be acutely aware of the consequences, which are actually very bad.