最终目标是指定一个类的合同,该类驻留在我无法控制的外部程序集中(即我不能直接向该类添加合同).
到目前为止我尝试了什么:
ContractClassFor属性.
不起作用,因为目标类必须指向合同类.
通过对自动生成的方法进行逆向工程来手动构建合同引用程序集(即MyAsm.Contracts.dll).
不起作用,因为在我编译之后,重写器开始并且方便地剥离ContractDeclarativeAssembly属性,这使得组件无法被工具识别为"合同参考组件".我无法找到一种方法来关闭重写器.
创建一个具有相同名称,版本,强名称(如果有)和其他属性作为目标程序集的"假"程序集,并在其中放置具有相同命名方法的同名类.然后在打开"构建合同引用"选项的情况下编译该程序集,然后获取生成的合同引用程序集并使用它.
由于某种原因,这也没有用,虽然我不知道究竟是什么原因.静态检查器只是忽略了我的smartypants生成的引用程序集,就好像它不存在一样.
还有一件事,以防万一重要:目标程序集是为.NET 2.0编译的,我无法为4.0重新编译它.
更新
编写一个定义合同的"包装"库是不可能的.
首先,它需要编写很多额外的代码.但即使你把它放在一边,也可能是一个重要的性能损失:我必须(可能)为每个"遗留"类型创建包装类,从我的"遗留"方法中用作返回类型.但即使这不是故事的结尾.想象一下,某些方法可能会返回对基接口的引用,然后调用代码可能会将它们转换为派生接口,以查看该对象是否支持更多功能.我如何包装那些?我可能必须Cast<T>()在我的包装类上提供自定义方法,它将尝试转换底层类/接口,并在成功时返回结果包装器.最后,我的整个代码库将变得如此复杂,无论如何它可能都不值得.
另一方面,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# 可以处理契约。