托管C++的一次编程经历

最近我发现,从前用一个C#编写的文件管理程序在处理大批量文件的时候,其内存占用量过高(数百兆),而且性能也很不稳定(忽快忽慢,估计和垃圾收集机制有关)。考虑程序本身的因素之后,觉得已经没有多少优化余地,因此能做的就是用C++改写其中文件处理的关键部分,以解决上述问题。

由上所述,为自己定的目标如下:
1、界面部分保留C#的代码;
2、文件处理过程用C++例程和Windows API改写;
3、为文件处理过程提供托管接口,给C#调用。

因为从前了解过Managed C++的内容,所以开始的部分很顺利:创建一个.Net类库,往里面添加代码就是了。

然而程序写到中间的时候,各种奇怪的问题开始浮现。有些比较简单,编译器告诉我MessageBoxA这个函数不对,这一看就是宏在添乱,但是怎么解决呢?总不能因此就不要windows.h吧?后来还是用google大法找到了答案,微软说必须#undef MessageBox。Sigh!多么奇妙的解决办法,我开始明白为什么C++在.Net中沦为二流语言了。

但是最关键的问题还是C++运行库似乎无法和管理代码并存,否则的话非常容易看到一大堆的链接失败信息。起初我的解决办法是不用任何C++函数,你不让我new 和delete,我用HeapAlloc分配内存总行吧?但是后来发现这样不可行,因为稍微复杂一点的程序中还是无法完全避免调用C++。辗辗转转,终于找到这么一篇文章:

将C++托管扩展项目从纯粹的中间语言转换成混合模式

http://www.vckbase.com/document/viewdoc/?id=1403

喏,看过这篇文章以后我得说这种解决办法一点也不优雅,不过它确实可行。好啦,眼下不要计较那么多,用文中的办法的确可以让程序工作起来了。

现在,这个改写过的程序可以正常运行,而且不管是内存空间还是运行效率,都的确是比原来好得多。不过经历过这么一段挫折以后,我对托管程序倒是多了些新的想法。对于.Net,目前我最欣赏它的地方还是:以组件化和代码重用来说,.Net让这些工作更加方便、也更不容易出错了。但是.Net庞大的资源消耗还是让我对它爱不起来,以一般的小程序来说,用MFC编写的话可能占用2~5M的内存,如果用WTL的话大约只用MFC的一半,但是用.Net来编写的话,程序一启动就占用10多兆的空间,运行时更多。当然单个程序来看的话10多兆不算什么,但是如果我要同时运行多个大型程序呢?微软的LongHorn之所以硬件要求高的吓人,我想多半也因为M$坚持要将LongHorn转向管理环境有关吧,否则的话去掉WinFS的长角并没有太多革命性的东西,也实在没有成为这么可怖的硬件杀手。

另外就是关于托管C++的话题。托管C++在.Net的世界中是名副其实的二等公民,这一点我有深切的感受,在网上关于MC的资料比起C#来说简直是九牛一毛,和VB.Net相比也颇有不如。用过MC的程序员似乎还没有一个说它好用的(以我看到和听到的而言)。MC的语法确实够丑陋,不过我自己倒不是很在意这一点,只要它能工作——但是我也不想经常和无盐打交道,因此我一般把MC用在接口这一级,内部实现尽量使用纯粹的C++。只是这次的经历可以证明,让管理代码和非管理代码一起工作也不是件轻松的事情,在某些地方必须做出一些折衷和妥协。从某种意义上讲,这样其实也很锻炼能力,但是没有创造性的工作还是少一些为好,程序员把精力花在这些琐碎的地方并不太值得。

经过这次折腾我也稍稍能够理解Stan Lipman为什么将C++/CLI如此设计,并不惜引入新的关键字;C++类和.Net类虽说都是类,概念上也基本上相同,但是实现中有如此多的细节不同,以至于让它们遵守相同的语法反而显得不太合适。我期待托管C++的问题能够在CLI中有一个比较完满的解决,但是就现在看到的资料来看,让托管代码和非托管代码在同一个模块中工作还是要涉及很多缠人的细节。这个世界总是不够完美——我现在能说的也就是这些了。

你可能感兴趣的:(C#和dotNet,Framework,C++)