为什么不能通过.NET中的COM使用.NET COM库?

Ara*_*ion 13 .net com

现在,我知道如果库是在.NET中,通过COM访问它有点没有意义,但是,我有点困惑,因为如果我要求某人写一个库并通过COM公开它,那么任何人都应该可以自由地使用任何语言.

对我来说,编写COM库的语言并不重要,为什么它重要?

作为参考,当您在.NET库生成的.tlb文件上使用tlbimp时会发生这种情况:

C:\dev>tlbimp test.tlb
Microsoft (R) .NET Framework Type Library to Assembly Converter 4.0.30319.1
Copyright (C) Microsoft Corporation.  All rights reserved.

TlbImp : error TI1029 : Type library 'test' was exported from
a CLR assembly and cannot be re-imported as a CLR assembly.
Run Code Online (Sandbox Code Playgroud)

另外,我的测试COM库使用IUnknown,仅支持早期绑定的COM互操作.

j__*_*__m 16

tlbimp只是问题的开始.

每个COM可见的.NET对象都实现IManagedObject.每次尝试通过COM接口调用对象时,.NET都会为IManagedObject执行QueryInterface,如果成功,则直接打开并直接访问该对象.以这种方式消除互操作呼叫被认为是性能优化.

这是基于COM的互操作方案中的一个严重问题,其中可以用.NET语言实现多个组件.如果每个.NET组件都实现了自己的tlbimp生成的COM接口版本,那么它们将无法使用该接口相互通信.尽管每个tlbimp的接口副本都具有相同的COM GUID,但.NET认为它们是单独的接口.这个问题的"正确"解决方案是在主互操作程序集中定义COM接口,并让每个.NET实现的组件使用该接口的相同副本,但如果组件开发人员之间没有协调,则不太可能发生.

Microsoft开发人员曾在http://blogs.msdn.com/b/jmstall/archive/2009/07/09/icustomqueryinterface-and-clr-v4.aspx以及.NET 4解决方案中突出强调了此问题,但它基于预发布版本,并且在决赛中不起作用.我不知道微软已经承认了其他任何地方.

一种解决方案是放弃.NET-to-.NET场景中的接口并改为使用反射.这可能在许多情况下有效,但当然不是很有效.可能最好的解决方案是使用非托管代码来聚合每个托管组件,并拒绝对IManagedObject的QueryInterface的尝试.这类似于上面博客条目中描述的内容,但不依赖于那些不再像该博客中描述的那样工作的.NET功能.

.NET互操作行为是IMO,非常糟糕,并且明显违反了COM规则(相同的IID ==相同的接口,不应该关心对象的实现语言).但是.NET从一开始就表现得很好,而且这种行为所困扰的开发人员的反馈并没有改变.NET团队中任何人的想法.


Han*_*ant 6

Tlbimp从类型库中可以看到它是由.NET程序集生成的。它只是阻碍了您正在尝试做的事情。如果您要使用.NET程序集,则没有任何意义,只需添加对其的引用。

您可以使用后期绑定的COM来欺骗计算机,这最容易用C#中的dynamic关键字完成。但这仍然不能使CLR蒙上阴影,它可以看到它与托管程序集互操作,并且实际上不会创建COM可调用包装器。通常,您这样做是为了编写测试程序来测试您的COM服务器。这意味着您的测试实际上并未测试COM服务器在实践中的使用方式。根本就不会测试像变体转换为对象然后再返回等非常基本的事情。在生产中使用装配体时,可能会给您带来非常不愉快的惊喜。