开发者

Why is marking an assembly ComVisible(true) discouraged?

开发者 https://www.devze.com 2023-01-08 04:44 出处:网络
I have always marked my .NET assemblies as visible to COM with [assembly: ComVisible(true)], thinking that I never know when someone might need to call them from COM.I also started using FxCop and sta

I have always marked my .NET assemblies as visible to COM with [assembly: ComVisible(true)], thinking that I never know when someone might need to call them from COM. I also started using FxCop and started seeing this warning from code analysis:

CA1017 : Microsoft.Design : Because 'MyLibrary.dll' exp开发者_如何学Pythonoses externally visible types, mark it with ComVisible(false) at the assembly level and then mark all types within the assembly that should be exposed to COM clients with ComVisible(true)

Is there some reason why you would not simply want all of your public types exposed to COM? I'm guessing that there is, but I cannot imagine what this reason is. If anything, it seems markedly inconvenient.


The key thing is that exporting a COM interface does not come for free as there are incompatibilities and requirements that must be met. This has to be both thought about and then maintained. (Warning CA1017 is alluding to this.)

Therefore I have always worked with the "opt-in" philosophy rather than "opt-out" i.e. rather than making everything COM visible, I mark the assembly as not COM visible. I then concentrate on exposing types\members selectively (i.e. by opting in), and make sure that the API that is exposed is sane for COM (e.g. COM does not support generics, method overloading or constructors which take parameters) and also that it has been tested with COM in mind. In this way exposing an API to COM is done in a rigorous, tested, bounded and maintainable fashion.

This is the opposite to making everything COM visible and then worrying about any potential issues later, bearing in mind that if you have exposed everything then there may be couplings with users of your COM interface that you did not expect and will now have difficulty backing out of.

From memory a couple of examples of unexpected consequences:

  1. When exporting overloaded methods, they are exported and named by default with a sequence number e.g. OverloadedMethod1, OverloadedMethod2, etc. If you refactor your code and change the order of your methods or insert an overload, etc, you are then in trouble with anyone that has used these methods from your previous COM interface. OverloadedMethod1 and OverloadedMethod2 may have been swapped.

  2. Classes which are exposed to COM must have a parameterless constructor. If there is not a unit test in place that maintains this contract, then it is easy to change that class at a later date so that it does not have a parameterless constructor and thus breaks your COM interface users.


With the advent of Generics and other advanced types, it is more common now for methods to expose types that can't be COM visible than it is for them to expose types that can.

The recommended method in CA1017 is intended to encourage you to expose only those types that you intend to be exposed to COM.


For reference, if no assembly level ComVisibleAttribute is applied, all public classes are assumed to be COM Visible. Failing to mark an assembly as [assembly: ComVisible(false)] will often result in the following Code Analysis warning, even for types that are not marked [ComVisible(true)]:

CA1405: COM visible type base types should be COM visible


Marking the assembly not COM visible is very useful when you have a bunch of public classes inside that you don't want to expose to COM. Those classes could for example be proxy classes of a web serive your assembly consumes. Either you thoroughly mark each such class not COM visible or you just mark the assembly not COM visble and then mark each class to expose to COM. That's a much higher degree of control and less maintenance.


It is easy and given on MSDN. This is the way how to fix this warning:

using System;
using System.Runtime.InteropServices;

[assembly: ComVisible(false)]
namespace InteroperabilityLibrary
{
   [ComVisible(false)]
   public class BaseClass
   {
      public void SomeMethod(int valueOne) {}
   }

   // This class violates the rule.
   [ComVisible(true)] 
   public class DerivedClass : BaseClass
   {
      public void AnotherMethod(int valueOne, int valueTwo) {}
   }
}

If Base class is in any dll which you are referring in your code. Then, Make [COMVisibible(True)] for derived class. It works in my scenario.

0

精彩评论

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