.NET代码约定 - 当两者在同一解决方案中时,ProjectA.exe找不到ProjectB.Contracts.dll

时间:2016-04-19 18:26:56

标签: c# msbuild code-contracts

我在VS2013中有一个C#解决方案,并安装了Code Contracts扩展。在我的解决方案中,我有一个应用程序项目(ProjectA)和一个类库项目(ProjectB)。 ProjectA引用ProjectB,并且ProjectB的大多数公共成员都有与之关联的合同。

我可以毫无问题地从ProjectA访问ProjectB的大多数成员,但在一个属性上我得到FileNotFoundException,消息"无法加载文件或程序集& #39; ProjectB.Contracts,Version = ....'或其中一个依赖项。"

以下是融合日志所说的内容:

  

===预绑定状态信息===

     

日志:DisplayName = [SolutionName] .ProjectB.Contracts,Version = 1.0.5953.23121,Culture = neutral,PublicKeyToken = null(完全指定)

     

日志:Appbase = [SolutionDir] / [SolutionName] .ProjectA / bin / Debug /

     

日志:初始PrivatePath = NULL调用程序集:[SolutionName] .ProjectC,Version = 1.0.5953.23122,Culture = neutral,PublicKeyToken = null。

     

XXX

     

日志:此绑定在默认加载上下文中启动。

     

日志:使用应用程序配置文件:[MyDocuments] [SolutionName] [SolutionName] .ProjectA \ bin \ Debug [SolutionName] .ProjectA.vshost.exe.config

     

日志:使用主机配置文件:

     

日志:使用C:\ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319 \ config \ machine.config中的计算机配置文件。

     

日志:此时策略未应用于引用(私有,自定义,部分或基于位置的程序集绑定)。

     

日志:尝试下载新网址   [SolutionDir] / [解决方案名称] .ProjectA / bin中/调试/ [解决方案名称] .ProjectB.Contracts.DLL。

     

日志:尝试下载新网址   [SolutionDir] / [解决方案名称] .ProjectA / bin中/调试/ [解决方案名称] .ProjectB.Contracts / [解决方案名称] .ProjectB.Contracts.DLL。

     

日志:尝试下载新网址   [SolutionDir] / [解决方案名称] .ProjectA / bin中/调试/ [解决方案名称] .ProjectB.Contracts.EXE。

     

日志:尝试下载新网址   [SolutionDir] / [解决方案名称] .ProjectA / bin中/调试/ [解决方案名称] .ProjectB.Contracts / [解决方案名称] .ProjectB.Contracts.EXE。

此解决方案中唯一的引用是标准Framework库,此解决方案中的其他项目以及另一个第一方库(仅引用System.dll)。我已尝试清理和重建此解决方案中的所有项目,以及其他第一方库。

我很困惑,原因有几个。

  1. 在输出窗口中,我可以看到所有ProjectA和ProjectB的引用(及其引用)都已加载。
  2. 具有类似合同的其他看似相似的方法和属性不会引起任何问题。此外,我已经在几个解决方案中使用了代码合同数月,我还没有遇到过。
  3. 合同代码是否已经重新编译成ProjectB.dll?为什么ProjectA甚至需要知道有一个.Contracts库? (除智能分析和静态分析外)
  4. 有谁知道这里会发生什么?

    编辑:解决方案中的所有项目都面向.NET 4.0和#34;任何CPU"。

1 个答案:

答案 0 :(得分:1)

以下是我试过的一些不起作用的事情:

在ProjectA的项目设置上,在Code Contracts选项卡上,我尝试将 ... ProjectB \ bin \ Debug \ CodeContracts 添加到字段额外合同库路径 。这并没有改变任何事情。

我还尝试手动添加对ProjectB.Contacts.dll的引用。这会将我的[]变为FileNotFoundException。这让我觉得这个问题可能是由于代码合同重写者的错误造成的。输入ILSpy

导致此问题的合同基本上是原始源代码:

MissingMethodException

但是我把它放在这样的合同缩写方法中:

Contract.Requires<ArgumentNullException>(collection.All(x => x != null));

并在类似这样的类中调用它:

public static class PreCondition {
    [ContractAbbreviator]
    public static void NotIsOrHasNull<T>(IEnumerable<T> collection){
        Contract.Requires<ArgumentNullException(collection != null,   
            "Collection cannot be null.");
        Contract.Requires<ArgumentNullException>(collection.All(x => x != null), 
            "Collection cannot contain null.");
    }
}

在ILSpy中查看麻烦的方法调用时,我看到它试图调用名为public class Class1{ public void DoStuff(IEnumerable<T> collection){ PreCondition.NotIsOrHasNull(collection); foreach (var x in collection){ //Stuff } } } 的实例方法,而不是静态方法Class1.NotIsOrHasNull

解决方案:

我更改了PreCondition.NotIsOrHasNull类,将LINQ表达式移动到自己的PreCondition函数中,并更改了合约缩写器以调用该方法。

Pure

现在,public static class PreCondition { [Pure] public static Boolean CollectionContainsNull(IEnumerable<T> collection){ Contract.Requires<ArgumentNullException(collection != null); if (typeof(T).IsValueType) return false; return collection.Any(x => Object.Equals(x, null)); } [ContractAbbreviator] public static void NotIsOrHasNull<T>(IEnumerable<T> collection){ Contract.Requires<ArgumentNullException(collection != null, "Collection cannot be null."); Contract.Requires<ArgumentNullException>(!CollectionContainsNull(collection)), "Collection cannot contain null."); } } 中的方法调用正常,IL在ILSpy中看起来是正确的。

+1到ILSpy!