我想采取一种渐进的方法,我们慢慢地移动部分代码
这是唯一现实的方法。
首先,你使用什么样的版本控制?(如果您使用允许您进行实验并查看哪些工作有效的分支版本控制,同时最大限度地减少损害您的代码的风险;其他人也可以,但您必须非常小心,具体取决于您使用的内容)。
编辑:我刚刚看到你正在使用 SVN。如果您有自由这样做,那么迁移到 mercurial 或 git 可能是值得的(更改为您可以使用代码库做的事情提供了巨大的飞跃)。
例如,将新功能写入 C# 并将其编译到可以从旧应用程序引用的库或 dll 中。
那……不一定是个好主意。C# 代码可以公开可在 C++ 中访问的 COM 接口。用 C++ 为用 C# 编写的模块编写客户端代码可能很有趣,但您可能会发现它很费力(就工作收益比而言);它也很慢且容易出错(与为用 C++ 编写的模块编写 C# 客户端代码相比)。
最好考虑用 C# 创建一个应用程序框架,并使用用 C++ 编写的模块(已经)来实现核心功能。
这可能吗?最好的方法是什么?
是的,这是可能的。
有多少人参与了这个项目?
如果有很多,最好的方法是让几个(两个?四个?)在新的应用程序框架上工作,其余的照常继续。
如果很少,您可以考虑让一个人负责,或者让更多的人兼职。
分配给每个(旧代码维护和新代码开发)的人员/工作量的百分比应取决于团队的规模和您的优先级(转换是低优先级问题吗?是否必须在给定日期之前完成?)
做到这一点的最好方法是开始调整代码模块以在多个场景中使用(旧代码和新代码)并继续并行开发(同样,这将通过使用分支分布式版本控制系统)。
以下是我的做法(迭代开发,中间有小步骤和大量有效性检查):
在旧代码库中选择一个功能模块(与 GUI 无关的东西)。
从步骤 1 中选择的模块中删除 MFC 代码(以及 VS2010 Express 中不可用的其他库 - 如 ATL)引用。
不要尝试用自定义代码重写 MFC/ATL 功能,除非进行小的更改(也就是说,决定创建自己的 GUI 框架是不可行的,但可以决定编写自己的 COM 接口指针包装器,类似于ATL 的 CComPtr)。
如果代码严重依赖库,最好尽可能将其分离,然后将其标记为将来使用新技术重写。无论哪种方式,对于一个严重依赖于 MFC 的库,你最好使用其他东西(C#?)重写代码。
尽可能减少与所选模块的耦合(确保代码在单独的库中,明确决定模块向客户端代码公开哪些功能)并仅通过确定的公开接口(在旧代码中)访问分隔功能。
确保旧代码库仍然适用于修改后的模块(测试 - 最终自动化此模块的测试) -如果您需要在发布新版本之前仍留在市场上,这一点至关重要。
在维护当前应用程序的同时,启动一个新项目(基于 C#?),实现 GUI 和您需要现代化的其他部分(如严重依赖 MFC 的部分)。这应该是一个薄层应用程序,最好与业务逻辑无关(应尽可能保留在遗留代码中)。
根据旧代码的功能和您定义的接口,对部分代码使用 C++/CLI 而不是 C# 可能是有意义的(它可以使用本机 C++ 指针和托管代码,允许您在以下情况下轻松转换在托管 .NET 代码和 C++ 本机代码之间进行通信)。
使新应用程序使用在步骤 1 中选择的模块。
选择一个新模块,返回步骤 2。
优点:
几点注意事项:
如果你不使用分布式分支版本控制系统,你最好一次只处理一个模块。如果您使用分支/分布式源代码控制,您可以将不同的模块分发给不同的团队成员,并在每次移植新内容时集中更改。
清楚地划分每个步骤非常重要(这样您就可以将更改回滚到上一个稳定版本,尝试新事物等等)。这是另一个在 SVN 中难以解决而在 Mercurial / Git 中容易解决的问题。
在开始之前,将所有项目文件的名称更改为具有 .2005.vcproj 扩展名,并对解决方案文件执行相同操作。创建新项目文件时,对项目文件和解决方案使用 .2010.vcxproj 执行相同操作(如果转换解决方案/项目,您仍应执行此操作)。这个想法是你应该在任何时候同时拥有并行和开放的任何你想要的东西。您不必为了切换 IDE 而在源代码管理中对不同的标签/标签/日期进行源代码树更新。
Edit2:我们已经研究过用 C# 编写 COM 包装的组件,但是没有 COM 经验,这既可怕又复杂。
您仍然可以通过编写包装器代码来做到这一点(例如,用于 COM 接口的小型模板智能指针类不会出错 - 类似于 ATL 中的 CComPtr)。如果您将 COM 代码隔离在一些包装器后面,您可以编写客户端代码(与 COM 无关)而(几乎)没有问题。
是否可以生成一个带有直接 C 接口的 C# dll,其中隐藏了所有托管的优点?还是 COM 是必要的邪恶?
从来没听说过。如果您打算使用用 C# 编写的服务器代码和用 C++ 编写的客户端代码,我认为 COM 将是一个必要的邪恶。
反过来也是可能的。