为遗留库创建代码合同

最终目标是指定一个类的合同,该类驻留在我无法控制的外部程序集中(即我不能直接向该类添加合同)。

到目前为止我尝试了什么:

  1. ContractClassFor属性。
    不起作用,因为目标类必须指向合同类。

  2. 通过对自动生成的程序集进行逆向工程来手动构建合同引用程序集(即MyAsm.Contracts.dll)。
    不起作用,因为在我编译之后,重写器启动并方便地剥离ContractDeclarativeAssembly属性,这使得程序组件无法识别为“合同引用程序集”。 而且我找不到关闭转码器的方法。

  3. 创建一个具有相同名称,版本,强名称(如果有)和其他属性作为目标程序集的“假”程序集,并在其中放置具有相同命名方法的同名类。 然后在打开“构建合同引用”选项的情况下编译该程序集,然后获取生成的合同引用程序集并使用它。
    由于某种原因,这也没有用,虽然我不知道究竟是什么原因。 静态检查器只是忽略了我的smartypants生成的引用程序集,就好像它不存在一样。

还有一件事,以防万一重要:目标程序集是为.NET 2.0编译的,我不能为4.0重新编译它。

更新

编写一个定义合同的“包装”库是不可能的。

首先,它需要编写很多额外的代码。 但即使你把它放在一边,也可能是一个重大的性能损失:我必须(可能)为每个“遗留”类型创建包装类,从我的“遗留”方法中用作返回类型。 但即便如此,也不是故事的结局。 想象一下,某些方法可能会返回对基接口的引用,然后调用代码可能会将它们转换为派生接口,以查看该对象是否支持更多function。 我如何包装那些? 我可能必须在我的包装类上提供自定义Cast()方法,它们将尝试转换底层类/接口,并在成功时返回结果包装器。 最后,我的整个代码库将变得如此复杂,无论如何它可能都不值得。

另一方面,CC团队本身已经成功解决了这个问题:他们为mscorlib,System.Core和其他一些系统组件提供了合适的合同参考组件,不是吗? 他们是如何建立起来的? 如果他们能够做到这一点,那么我认为没有任何理由说明我不应该采取相同的技巧。

哦,实际上,我确实看到了一个原因:我不知道该怎么做。 🙂 – Fyodor Soikin 18秒前编辑

你可能差不多有(2)。 请务必关闭您手动构建的C#程序集的合同重写。 关闭所有运行时检查和静态分析,重写器不应该启动。将它放在所有其他CodeContracts程序集的任何地方,例如对于/bin/X.dll,进行一个转到/ bin /的程序集CodeContracts / X.Contracts.dll。

请参阅http://social.msdn.microsoft.com/Forums/en-US/codecontracts/thread/5fe7ad4e-d4f1-4bb5-806e-a1e31f550181 。 你是对的 – 只需通过查看Reflector来创建所有正确的位,然后就可以了。 我想这样做是为了将合同添加到我的F#程序集中,直到F#可以处理合同。

解决方法可能是在代码和外部程序集之间创建“外观”层。 该层可以包含您将在外部代码上应用的所有合同。

如果您不想更改现有代码中的任何内容,我担心您无法做更多事情。