.NET 代码合同 - ProjectA.exe 在同一解决方案中找不到 ProjectB.Contracts.dll
.NET Code Contracts - ProjectA.exe cannot find ProjectB.Contracts.dll when both are in same solution
我在 VS2013 中有一个 C# 解决方案,安装了 Code Contracts 扩展。在我的解决方案中,我有一个应用程序项目 (ProjectA) 和一个 class 库项目 (ProjectB)。 ProjectA 引用了 ProjectB,并且大多数 ProjectB 的 public 成员都有与之关联的合同。
我可以毫无问题地从 ProjectA 访问 ProjectB 的大部分成员,但是在一个 属性 上,我收到 FileNotFoundException
,消息为 "Could not load file or assembly 'ProjectB.Contracts, Version=....' or one of its dependencies."
融合日志的内容如下:
=== Pre-bind state information ===
LOG: DisplayName = [SolutionName].ProjectB.Contracts, Version=1.0.5953.23121, Culture=neutral, PublicKeyToken=null (Fully-specified)
LOG: Appbase = [SolutionDir]/[SolutionName].ProjectA/bin/Debug/
LOG: Initial PrivatePath = NULL Calling assembly : [SolutionName].ProjectC, Version=1.0.5953.23122, Culture=neutral, PublicKeyToken=null.
xxx
LOG: This bind starts in default load context.
LOG: Using application configuration file: [MyDocuments][SolutionName][SolutionName].ProjectA\bin\Debug[SolutionName].ProjectA.vshost.exe.config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL
[SolutionDir]/[SolutionName].ProjectA/bin/Debug/[SolutionName].ProjectB.Contracts.DLL.
LOG: Attempting download of new URL
[SolutionDir]/[SolutionName].ProjectA/bin/Debug/[SolutionName].ProjectB.Contracts/[SolutionName].ProjectB.Contracts.DLL.
LOG: Attempting download of new URL
[SolutionDir]/[SolutionName].ProjectA/bin/Debug/[SolutionName].ProjectB.Contracts.EXE.
LOG: Attempting download of new URL
[SolutionDir]/[SolutionName].ProjectA/bin/Debug/[SolutionName].ProjectB.Contracts/[SolutionName].ProjectB.Contracts.EXE.
此解决方案中唯一的引用是标准框架库、此解决方案中的其他项目和另一个第一方库(仅引用 System.dll)。我已尝试清理并重建此解决方案中的所有项目,以及其他第一方库。
我很困惑有几个原因。
- 在输出 window 中,我可以看到 ProjectA 和 ProjectB 的所有引用(及其引用)都已加载。
- 其他看似相似的方法和具有相似契约的属性不会引起任何问题。此外,几个月来我一直在几个解决方案中使用 Code Contracts,但我还没有 运行 参与其中。
- 合约代码不应该已经重新编译成ProjectB.dll了吗?为什么 ProjectA 甚至需要知道有一个 .Contracts 库? (智能感知和静态分析除外)
有人知道这里发生了什么吗?
编辑: 解决方案中的所有项目都针对 .NET 4.0 和 "Any CPU"。
以下是我尝试过但没有奏效的一些方法:
在 ProjectA 的项目设置中,在代码合同选项卡上,我尝试将 ...ProjectB\bin\Debug\CodeContracts 添加到字段 Extra Contract Library路径。这并没有改变任何东西。
我还尝试手动添加对 ProjectB.Contacts.dll 的引用。这使我的 FileNotFoundException
变成了 MissingMethodException
。这让我觉得这个问题可能是由于代码合同重写者的错误造成的。输入 ILSpy.
导致问题的合同在原始源代码中基本上是这样的:
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.");
}
}
并在 class 中这样称呼它:
public class Class1{
public void DoStuff(IEnumerable<T> collection){
PreCondition.NotIsOrHasNull(collection);
foreach (var x in collection){
//Stuff
}
}
}
在 ILSpy 中查看麻烦的方法调用时,我看到它试图调用名为 Class1.NotIsOrHasNull
的实例方法,而不是静态方法 PreCondition.NotIsOrHasNull
.
解决方法:
我更改了 PreCondition
class 以将 LINQ 表达式移动到它自己的 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.");
}
}
现在 Class1
中的方法调用有效,并且 IL 在 ILSpy 中看起来是正确的。
+1 到 ILSpy!
我在 VS2013 中有一个 C# 解决方案,安装了 Code Contracts 扩展。在我的解决方案中,我有一个应用程序项目 (ProjectA) 和一个 class 库项目 (ProjectB)。 ProjectA 引用了 ProjectB,并且大多数 ProjectB 的 public 成员都有与之关联的合同。
我可以毫无问题地从 ProjectA 访问 ProjectB 的大部分成员,但是在一个 属性 上,我收到 FileNotFoundException
,消息为 "Could not load file or assembly 'ProjectB.Contracts, Version=....' or one of its dependencies."
融合日志的内容如下:
=== Pre-bind state information ===
LOG: DisplayName = [SolutionName].ProjectB.Contracts, Version=1.0.5953.23121, Culture=neutral, PublicKeyToken=null (Fully-specified)
LOG: Appbase = [SolutionDir]/[SolutionName].ProjectA/bin/Debug/
LOG: Initial PrivatePath = NULL Calling assembly : [SolutionName].ProjectC, Version=1.0.5953.23122, Culture=neutral, PublicKeyToken=null.
xxx
LOG: This bind starts in default load context.
LOG: Using application configuration file: [MyDocuments][SolutionName][SolutionName].ProjectA\bin\Debug[SolutionName].ProjectA.vshost.exe.config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL [SolutionDir]/[SolutionName].ProjectA/bin/Debug/[SolutionName].ProjectB.Contracts.DLL.
LOG: Attempting download of new URL [SolutionDir]/[SolutionName].ProjectA/bin/Debug/[SolutionName].ProjectB.Contracts/[SolutionName].ProjectB.Contracts.DLL.
LOG: Attempting download of new URL [SolutionDir]/[SolutionName].ProjectA/bin/Debug/[SolutionName].ProjectB.Contracts.EXE.
LOG: Attempting download of new URL [SolutionDir]/[SolutionName].ProjectA/bin/Debug/[SolutionName].ProjectB.Contracts/[SolutionName].ProjectB.Contracts.EXE.
此解决方案中唯一的引用是标准框架库、此解决方案中的其他项目和另一个第一方库(仅引用 System.dll)。我已尝试清理并重建此解决方案中的所有项目,以及其他第一方库。
我很困惑有几个原因。
- 在输出 window 中,我可以看到 ProjectA 和 ProjectB 的所有引用(及其引用)都已加载。
- 其他看似相似的方法和具有相似契约的属性不会引起任何问题。此外,几个月来我一直在几个解决方案中使用 Code Contracts,但我还没有 运行 参与其中。
- 合约代码不应该已经重新编译成ProjectB.dll了吗?为什么 ProjectA 甚至需要知道有一个 .Contracts 库? (智能感知和静态分析除外)
有人知道这里发生了什么吗?
编辑: 解决方案中的所有项目都针对 .NET 4.0 和 "Any CPU"。
以下是我尝试过但没有奏效的一些方法:
在 ProjectA 的项目设置中,在代码合同选项卡上,我尝试将 ...ProjectB\bin\Debug\CodeContracts 添加到字段 Extra Contract Library路径。这并没有改变任何东西。
我还尝试手动添加对 ProjectB.Contacts.dll 的引用。这使我的 FileNotFoundException
变成了 MissingMethodException
。这让我觉得这个问题可能是由于代码合同重写者的错误造成的。输入 ILSpy.
导致问题的合同在原始源代码中基本上是这样的:
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.");
}
}
并在 class 中这样称呼它:
public class Class1{
public void DoStuff(IEnumerable<T> collection){
PreCondition.NotIsOrHasNull(collection);
foreach (var x in collection){
//Stuff
}
}
}
在 ILSpy 中查看麻烦的方法调用时,我看到它试图调用名为 Class1.NotIsOrHasNull
的实例方法,而不是静态方法 PreCondition.NotIsOrHasNull
.
解决方法:
我更改了 PreCondition
class 以将 LINQ 表达式移动到它自己的 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.");
}
}
现在 Class1
中的方法调用有效,并且 IL 在 ILSpy 中看起来是正确的。
+1 到 ILSpy!