在.Net平台进行程序设计时,经常遇到基于Native C++,已经开发出很多类库,而现在需要用C#语言调用Native C++类库。这种情况在金融公司的量化投资部门经常发生。原因是,金融业务系统的对计算性能极其敏感,所以很多计算模块是用Native C++实现;然而用户操作界面用一般采用C#开发,理由很简单,C#开发效率确实胜过C++。本文围绕C#语言调用C++代码存在问题进行讨论。
笔者认为C#调用C++类库的障碍主要是验证C#语言是否可以操作内存,这也是托管代码和非托管代码的本质区别。具体来讲,要解决好三个问题:
a. C#是否可以传地址给C++
b. C#与C++是否互相可读内存中的数据
c. C#与C++是否互相可写内存中的数据
下面将围绕这三个问题分系列展开讨论。首先,简单介绍C#调用C++类库的主要技术。
连接托管世界与非托管世界的交互技术主要有四种:
1. 平台调用技术:直接通过P/Invoke 调用Native C++ Dll (static extern, DllImport)
2. C++ Interop:C++/CLI Wrapper Class
3. COM Interop
4. 采用Reflection.Emit技术,直接调用Native C++
上面四种方法中,前两种方式比较适合我们的实际情况。接下来,重点介绍前两种调用方式的使用场景。
选择平台调用技术还是C++ Interop技术来与非托管代码进行交互,取决于具体的需求。下面分别列举两种技术的使用场景。
1. 平台调用技术(P/Invoke)
1) 在源代码获取不到的情况下,平台调用技术是唯一选择。
2) 非托管函数只包含blittable类型数据。
2. C++ Interop
1) 需要在托管代码中大量使用非托管函数或类。
2) 需要在托管代码中使用非托管代码的功能且对性能要求较高时。
3) 需要封送一些非常复杂的自定义数据类型以及希望获得更好的类型安全性
在金融行业,多数计算类库以Dll的方式提供。为支持C#的调用而去改变现有的源代码不是推荐的方式。所以,对于C#调用C++ Library这个Case应该更适合用平台交互技术。后续文章,笔者将详细介绍C#通过P/Invoke调用C++库的方法。