类版本化

时间:2013-02-25 18:34:19

标签: vb.net versioning

我正在寻找一种简洁的方法来对我的代码库进行增量更新,而不会破坏向后兼容性。这可能意味着向类添加新成员,或更改现有成员以提供其他功能。有时我需要更改一个成员,以致它会破坏现有代码(例如重命名方法或更改其返回类型),所以我不想在发货后触摸任何现有类型。

我目前设置的方式是通过继承和多态来创建一个扩展该类之前“版本”的新类。

class diagram

这种方法的工作方式是根据StatusResult属性的实际值创建StatusResultVersion3的适当版本(例如ProtocolVersion),并将其作为{的实例返回{1}}。

因为.NET似乎没有类版本控制的概念,所以我必须自己编写:将版本号附加到类名的末尾。这无疑会让你畏缩。我可以很容易地想象自己在放大图表后睁大眼睛。但它的确有效。我可以添加新成员并覆盖现有成员,而不会引入任何代码更改。

有没有更好的方法来修改我的课程?

4 个答案:

答案 0 :(得分:1)

在考虑现有代码和程序集更新时,通常有两种方法:

  1. Regression Testing

    对于非破坏性更改,这是一种很好的方法,您可以简单地重载函数以提供新参数等.Visual Studio有一些非常先进的unit testing capabilities,使您的回归测试相对容易和自动化。

  2. Assembly Versions

    如果您的更改将开始破坏,例如重写某些实用程序的工作方式,那么就应该开始新的程序集版本了。 .NET非常适合使用汇编版本。您可以将版本化程序集部署到不同的文件夹,以便现有代码可以继续引用旧版本,而新代码可以利用新版本中的功能。

答案 1 :(得分:1)

接口的问题在于,一旦发布,它们基本上就是一成不变的。引用Anders Hejlsburg:

  

...就像在界面中添加方法一样。在发布接口之后,它实际上是不可变的,因为它的任何实现都可能具有您要在下一个版本中添加的方法。所以你必须改为创建一个新界面。

因此,您永远不能只更新界面,您需要创建一个全新的界面。当然,您可以使用单个类实现两个接口,因此与(比方说)多态类相比,您的可维护性工作量相当低,其中您的代码将随着时间推移在多个类之间展开。

多个接口还允许您以类不能的方式删除方法(当然,您可以弃用它们,但在几次迭代后可能会导致非常嘈杂的智能感知)

我个人倾向于在每个程序集版本中拥有完全独立的界面版本。

也就是说......

v 0.1.0.0

interface IExample
{
    String DoSomething();
}

v 0.2.0.0

interface IExample
{
    void DoSomethingElse();
}

你如何在幕后实现它们取决于你,但很可能它是相同的类,有不同的方法做类似的工作(否则,为什么使用相同的接口?)

所有旧代码都应引用0.1.x.x,新代​​码将引用0.2.x.x。关于唯一的问题是当您发现(比方说)安全漏洞并且需要将修复程序反向移植到早期版本时。这是一个体面的VCS进入的地方(个人偏好是TFS,但SVN或支持分支/合并的任何其他东西都可以)。

0.2分支中的修补程序合并回0.1分支,然后重新编译以生成(比方说)0.1.1.0

只要你坚持这样的过程:

  • 如果有任何重大更改(主要或次要构建将不会在构建/修订增量上更改),则主要或次要构建将增加
  • 如果较旧的程序应使用新的主要/次要版本,则使用publisher policies(相当于保证没有任何损坏,所以无论如何都要使用新版本)
  • 客户端应用程序中的引用应指向主要/次要版本,但不指定版本/构建

这会给你:

  • 没有遗留杂乱的干净代码库
  • 允许客户使用最新版本,如果没有任何代码更改,则无需更改代码
  • 防止客户端使用更新版本的程序集,这些程序集在重新编译之前会有重大更改(并且,希望在适当时更新其代码以利用新功能。)
  • 允许您发布以前版本的安全补丁

答案 2 :(得分:0)

OP解决了他的问题,如this comment所示:

  

最后,我使用了接口的想法,因为它允许我在一个类文件中保留多个版本的类成员。当我需要更新类时,我只需添加新接口,遮蔽已更改的成员,并更改某些方法的返回类型。由于多态性,这可以在不破坏向后兼容性的情况下工作。

答案 3 :(得分:0)

如果主要用于序列化,可以使用DataContractSerializers和DataAnnotations在.Net中实现。他们可以将对象的不同版本反序列化为同一个对象,以允许对同一个类的不同版本进行反序列化,从而使其无法映射的任何属性为空。