开发者

How to manage COM objects runtime in RAII style in C# programs?

开发者 https://www.devze.com 2023-03-26 22:37 出处:网络
My C# program uses a COM component that has a ton of various interfaces and subobjects. The problem is each time I retrieve some COM interface an RCW is created and that RCW exists for unknown time (u

My C# program uses a COM component that has a ton of various interfaces and subobjects. The problem is each time I retrieve some COM interface an RCW is created and that RCW exists for unknown time (until collected by GC). Each RCW holds some object in the COM server.

The COM component is an out-proc server, so its objects reside in a separate quite heavy-weight process that won't terminate until all objects residing in it are released. I want all object to be releases ASAP so that I know for sure that once I released the last object the out-proc server process terminates and no longer consumes system resources. That's not my paranoia - having several heavyweight processes consuming system resources, especially memory, is really bad for performance.

So far I crafted a generic class that implements IDisposable, accepts a reference to the object (RCW in fact) and calls Marshal.FinalReleaseComObject in Dispose implementation.

For the sake of this question let's temporarily ignore possible problems arising from using FinalReleaseComObject() - I'm aware of them and can tolerate them.

The real problem is I'm forced to either use using for all objects or to write finally clauses and call Dispose() there. It works, but code gets rather cluttered with lots of extra wiring and that bothers me big time.

For example, I need to assign a string to someObject.Params.ColorParams.Hint property - I can't just write

someObject.Params.ColorParams.Hint = whatever;

because for each accessor there will be a COM object that I need to get released, so I have this instead:

using( MyWrapper<IParams> params = new MyWrapper<IParams>( someObject.Params ) ) {
    using( MyWrapper<IColorParams> colorParams =
         new MyWrapper<IColorParams>( params.Controlled ) )
    {
        colorParams.Controlled.Hint = whatever;
    }
}

and that's the most trivial example - sometimes I need to access something five levels deep and then I 开发者_开发百科write a set of using statements five level deep.

Is there a more elegant solution to the problem?


Please see this answer to Clean up Excel Interop Objects with IDisposable by Hans Passant.

In summary, you don't need IDisposable at all. Just explicitly invoke garbage collection after all of your COM references have gone out of scope – i.e. not from the function that uses them but from the caller of that function.


I'm not sure I fully understand the problem, but if I do (code clutter) there are 2 possible solutions:

A wrapper method - You could define a simple method:

TResult Exec<TResult>(Func<TResult> func, params MarshalByRefObject comObjects)
{
  TResult res = default(TResult);
  try
  {
    res = func.Invoke();
  }
  catch (Exception e) { /* Log? */ }
  finally
  {
    foreach (MarshalByRefObject combObj in comObjects)
    {    /* release resources using common interface or reflection */ }
  }
}

Very much like the previous method, only using one of the many AOP frameworks to do it (e.g PostSharp)


c# and deterministic release of resources is generally troublesome at best.
Release of out of process COM objects is one example of the problem.

If you are happy to write some C++/cli code it at least has the option of stack semantics for managed heap objects. This avoids the need for using or finally wrapping as the compiler calls dispose for you when the object drops out of scope.

Of course it does bring you an otherwise noisier language than c#, header files ., ->, :: etc.

As a rule if your code is able to create and release the COM objects at local scope within a using block, I would stay in C# and put up with the using hassle.

If your code needs to keep COM objects as member variables I would move just those classes to c++/cli and take advantage of stack semantics for member variables that will automatically chain dispose calls for you.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号