Effective C# Item46:最小化互操作
在设计.NET时,充分考虑了当时使用其他语言或者平台编写的系统,为了使得这些系统可以集成到.NET中,添加了互操作的特性,但是互操作的优势很少,甚至还会给开发人员带来一些麻烦。
在所有的互操作策略中,当程序控制流在本地环境和托管环境的边界上穿越时,我们都必须为类型提供marshall服务,另外,互操作策略还要求我们自己明确声明方法参数,最后,当CLR在跨越互操作边界时,不能进行任何优化。
我们可以使用不同的互操作策略来逐步替换遗留系统,这其中的开销主要是开发进度和运行时性能。
使用互操作,我们需要考虑以下三方面的开销:1. 数据与托管堆和本地堆之间的marshall成本;2. 托管代码和非托管代码之间的切换代价; 3. 对于开发人员来说,要在混合环境下进行工作。
我们有以下三种方式可以在托管和非托管组件之间进行程序控制流程的切换:1. COM interop; 2. Platform Invoke; 3. 托管C++。
COM interop是利用现存COM组件最简单的互操作方式,但是它也是效率最低的一个,一般情况下,如果遗留系统是采用COM的,那么可以考虑这个方案,如果不是,就不需要考虑这个方案了。
Platform Invoke,也称作P/Invoke,这是调用Win32 API效率最高的方式,但是这种方式存在着缺点:我们需要在C#中自己声明每个使用P/Invoke调用的方法接口。调用的方法越多,需要开发人员手动编码声明的方法也就越多。总之,我们应该使用P/Invoke的方式来调用Win32函数。
最后一种互操作策略是使用托管C++,我们可以在C++编译器中带卡/CLR开关来编译托管代码和非托管代码的混合体,如果我们使用/CLR编译所有的本地代码,那么编译器生成的程序库中包含的将是MSIL,这意味着C++程序库不能直接被C#调用,我们必须在本地代码之上建立一个托管的C++程序库,从而在托管类型和费托管类型之间搭建一条桥梁,并为托管堆和非托管堆上的数据提供marshall支持。
互操作总是一件痛苦的事情,在进行互操作之前,我们需要认真的考虑是否可以重写本地应用程序,很多情况下,重写要更加简单快捷,但是如果需要进行互操作,那么需要根据情况,选择最节省时间的互操作策略。