我在 Visual Studio 2010 中有一个 C# WinForms 应用程序,供两个不同的客户使用。应用程序的基本功能对于每个客户都是相同的,但某些代码行(存储过程的名称、资源、某些行为)在版本之间是不同的。到目前为止,我将应用程序保留在同一个项目中,并在构建/发布时使用预处理器指令来切换要使用的部署。然而,该项目的范围已经扩大到不再可行的程度。
由于有这么多代码是共享的,我试图避免重复源代码文件。我想知道维护需要同时部署不同版本的应用程序的最佳方法是什么。
我在 Visual Studio 2010 中有一个 C# WinForms 应用程序,供两个不同的客户使用。应用程序的基本功能对于每个客户都是相同的,但某些代码行(存储过程的名称、资源、某些行为)在版本之间是不同的。到目前为止,我将应用程序保留在同一个项目中,并在构建/发布时使用预处理器指令来切换要使用的部署。然而,该项目的范围已经扩大到不再可行的程度。
由于有这么多代码是共享的,我试图避免重复源代码文件。我想知道维护需要同时部署不同版本的应用程序的最佳方法是什么。
使用接口来定义你的类。拥有一个接口意味着您可以拥有同一个接口的多个实现,每个客户端一个。这将要求您分析现有代码库并确定代码中可以定义这些接口的逻辑分隔。
然后,您可以根据客户端的需要加载接口。例如,您可以通过配置执行此操作。根据配置值加载 Implementation1 或 Implementation2。有很多很多方法可以完成这个特定的位。您应该阅读依赖注入、控制反转并查看 Ninject、Autofac、Unity 等工具。
一开始实际上可能很难考虑您是如何使用预处理器指令的,但是随着您的应用程序的增长,您将需要进行这种重构。请记住,如果您现在不这样做,那么随着您的应用程序变得更加复杂,这种重构将更加昂贵。
不同的功能应该是应用程序架构的一部分。如果您需要为不同的客户提供不同的功能,请将其抽象出来——创建一个封装行为的接口,然后在两个不同的程序集中以两种不同的方式实现它。然后(取决于您的部署机制),您可以使用一个 DLL 或另一个来发布您的应用程序。为了避免重新编译、添加引用等,您可以使用依赖注入框架,例如 Ninject、Castle Windsor、MEF 等。如果代码足够不同,那是一个“类似插件”的架构。
如果您谈论的是文本、颜色、基本差异,它们不应该是硬编码的,而是数据驱动的。如果您的应用程序连接了互联网,它可以在用户登录时下载适当的设置。否则,可以将指示文本/颜色/行为的内容放入特定于客户的配置文件中。您可以使用配置转换来简化该过程。
您可以通过使用某种资源、配置或属性文件来区分一些差异。我的意思是您在文件中存储某种值,例如在特定情况下使用的存储过程的名称。然后您的代码从文件中读取名称并运行它。您可以更改文件中的值,而无需为每个部署重新构建代码。