Welcome

首页 / 软件开发 / C# / Effecitve C#原则46:最小化与其它非托管代码的交互

Effecitve C#原则46:最小化与其它非托管代码的交互2010-12-13 博客园 Wu.Country@侠缘译在开发设计.Net时,MS所做的最聪明的修改之一就是他们意识到,如果没有 办法整合已经存在的代码到新的.Net环境中,那没没有人会接受这个新的平台。 MS知道,如果没有办法来利用已经存在的代码,这将阻止大家接受它。与其它非 托管代码的交互是可以工作了,但这是可交互唯一可以拿来说一下的有利的地方 。对于所有的交互策略,当操作流程在本地代码和托管代码之间的边界上进行传 送时,都要求强制提供一些 编组的信号。同时,交互策略强迫开发人员必须手 动的申明所有调用参数(译注:这里是说你根本不知道参数的数据类型,很多时 间你都只能以int32的方式传递所有参数,例如文件句柄,字符串指针等几乎是 所有的参数,都只有一个int32也就是IntPtr类型进行处理,当然这里认为是是 在32位机器上。)。最后,CLR还不能完成对托管代码和本地代码的边界上进行数 据传递时的优化。忽略采用本地代码或者COM对象时得到的好处吧,没有什么比 这更好的了(译注:我本人强烈反对这一原则。C++,COM在目前来说,绝对有它 生存的优势,我觉得应该充分利用这些优势,而不应该忽略它们)。但事实是交 互并不是总能工作的,很多时候我们还是在要已经存在的应用程序中添加新的功 能,提高而且更新已经存在的工具,或者在其它的地方要完成一个新的托管应用 程序与旧的应用程序交互。使用一些交互在实际应用中只会是减缓对旧系统的更 替。所以,有明白不同的交互策略之间有什么开销是很重要的。这些开销要同时 花在开发计划以及运行时性能中。有些,最后的选择是重写旧代码。还有一些时 候,你须要选择正确的交互策略。

在我讨论这个对你有用的交互策略之 前,我须要花一段来讨论放弃(just throw it out)策略。第五章,与.Net框架 一起工作,向你展示了一些.Net里已经为你创建好了的类和技术,你可以直接使 用或者派生。为你你想的很多,你可以确定一些类和你一些代码算法,并且全部 用C#重写。剩下存在的代码可以被.Net框架里已经存在的可能功能性的派生来取 代。这并不会总是在任何地方,任何时候都可以工作的,但这确实是一个经过认 真考虑过的迁移策略。整个第5章都推荐使用"throw it out“策略。 这一原则就专注于交互,而它确实是件痛苦的事情。

接下来,让我们假 设你已经决定重写全部代码并不实际。一些不同的策略要求你从.Net中访问本地 代码。你须要明白在本地代码和托管代码的边界上传递数据时的开销的低效。在 使用交互时有三个开销。首先就是数据集群处理,这在托管堆和本地代码堆之间 进行数据传递时发生。其次就是在托管代码和非托管代码进行交互时的大量数据 吞吐时的开销。你以及你的用户要承担这些开销。第三个开销就只是你自己的了 :你要在这个混合的开发环境中添加很多工作来实现交互。这也是最糟糕的一个 ,所以你的设计应该决定最小化这样的开销。

让我们开始讨论交互时在 性能上的开销,以及如何最小化这些开销。数据集群是最大的一个因数,就像是 网络服务或者远程操作一样,你须要尽可能使用笨重的(chunky)API而不是小巧 的(chatty )API(译注:数据集群是指你没有办法即时的与本地代码进行交互, 而有一个延时,这个延时就使用数据堆集起来一起处理,这样就使得你应该尽可 能少的与本地代码进行交互,而要选择一些一次可以处理较多数据的API)。你可 以用不同的方法来完成与非托管代码的交互。你可以重新修改已经存在的非托管 代码来创建一个笨重的API,更适合交互的API。常规的COM应用中是申明很多属 性,这样客户可以设置并修改COM对象内部的状态或者行为。每次的设置属性都 会集群数据,而且不得不穿越边界。(而且每在穿越交互边界时也会有thunks。) 这非常的低效,不幸的是,COM对象或者非托管库可能不受你控制。当这种情况 发生时,你须要完成更麻烦的工作。这时,你可以创建一个轻量级的C++库,通 过使用你所须要的chunkier API来暴露类型的功能。这就要增加你的开发时间了 (也就是第三个开销)。

当你封装一个COM对象时,确保你修改的数据类型 已经在本地代码一托管代码之间提供了最好的数据集群策略。有些类型可以很好 的比其它类型进行集群,试着限制用于在本地代码和托管代码之间进行传递的数 据类型,尽量使用blittable数据。blittable是指托管代码和本地代码都一样使 用的类型。数据内容可以直接拷贝而不用管对象的内部的结构。某些情况下,非 托管代码可能使用托管代码的代码。下面列出了blittable 类型:

System.Byte
System.SByte
System.Int16
System.UInt16
System.Int32
System.UInt32
System.Int64
System.UInt64
System.UIntPtr

另 外,任何的blittable类型的一维数组也是blittable类型。最后,任何格式化的 包含blittable类型的也是blittable类型。一个格式化的类型可以是一个用 StructLayoutAttribute明确定义了数据层次的结构,

[ StructLayout( LayoutKind.Sequential ) ]
public struct Point3D
{
public int X;
public int Y;
public int Z;
}