不正确的代码合同警告
Incorrect Code Contracts Warnings
我最近在一个非常大的项目中添加了代码合同。在通过几百个警告添加断言来安抚检查器之后,我留下了一些看起来明显不正确的警告!这可能是我能做的最简单的示例(完整代码是 here,如果您认为细节可能很重要):
protected Thing DoStuff(A a)
{
Contract.Requires(a != null);
//CodeContracts: Consider adding the postcondition Contract.Ensures(Contract.Result<Thing>() == null); to provide extra-documentation to the library clients
D outResult;
var result = DoSomething(a, out outResult);
if (result == null)
return null;
return new Thing(outResult, result);
}
这个建议显然是错误的(我有单元测试 return 来自这个函数的非空值来证明这一点)!唯一可能是真的是 "DoSomething" 也总是 return 为 null,但它没有就此提出任何建议。
编辑:我已经通过完全重写 DoSomething 方法以不使用输出结果(而是 returns 包含 outResult 和结果的元组)解决了上述问题。但是我仍然有其他我想解决的错误警告,并且可能有相同的根本原因。
所以这实际上是两个问题:
- 我我做错了什么或遗漏了什么明显的东西吗?
- 假设 CC 只是 错误 我能做些什么来缓解将来的此类问题 - 至少隐藏警告!
Re: Contract.Ensures 关于 return 值
在您的 MVCE 和生产代码中,在 'burden of proof' 上游之后,问题几乎肯定与调用的 SelectScript
扩展方法(或 MVCE 中的 DoSomething
)有关,静态分析器推断(可能不正确)扩展方法总是 return 为 null,因此在调用方法 SelectSingle
中第一个分支(也 returning null)将总是被选中,因此推荐 null 的后置条件。
我找不到 SelectScript
的代码,但在 VS 2013 更新 4 / CC 1.7.11202.10 上,我只能通过显式 return 只从 SelectScript
并启用 "Infer ensures" 静态检查选项,或者通过显式添加 Contract.Ensures(Contract.Result<ScriptReference>() == null);
到 SelectScript
,例如with 确保推断:
public static ScriptReference SelectScript(
this IEnumerable<KeyValuePair<float, KeyValuePair<string, string>[]>> tags,
Func<double> random,
Func<KeyValuePair<string, string>[], Type[], ScriptReference> finder,
out KeyValuePair<string, string>[] selectedTags,
Type t)
{
selectedTags = null;
return null;
}
在调用方法中产生相同的警告 SelectSingle
:
CodeContracts: Consider adding the postcondition Contract.Ensures(Contract.Result() == null); to provide extra-documentation to the library clients
然而,对我来说,分析器似乎确实正确地推断出以下代码具有 return null 和 non-null 的分支,并且不建议调用者使用前提条件:
public static ScriptReference SelectScript(
this IEnumerable<KeyValuePair<float, KeyValuePair<string, string>[]>> tags,
Func<double> random,
Func<KeyValuePair<string, string>[], Type[], ScriptReference> finder,
out KeyValuePair<string, string>[] selectedTags,
Type t)
{
Contract.Requires(random != null);
selectedTags = null;
return (random() > 0.5)
? null
: new ScriptReference();
}
Re: Contract.Ensures关于out值
出于兴趣,也可以使用 Contract.ValueAtReturn
将合约添加到 out
参数 -
reference,第 2.2.3 页 p8.
例如如果您仍然在 out 参数上收到警告,您可以使用 grek40 的想法通过将此添加到 SelectScript
:
来抑制调用者中的警告
Contract.Ensures(Contract.ValueAtReturn(out selectedTags) == null ||
Contract.ValueAtReturn(out selectedTags) != null);
我最近在一个非常大的项目中添加了代码合同。在通过几百个警告添加断言来安抚检查器之后,我留下了一些看起来明显不正确的警告!这可能是我能做的最简单的示例(完整代码是 here,如果您认为细节可能很重要):
protected Thing DoStuff(A a)
{
Contract.Requires(a != null);
//CodeContracts: Consider adding the postcondition Contract.Ensures(Contract.Result<Thing>() == null); to provide extra-documentation to the library clients
D outResult;
var result = DoSomething(a, out outResult);
if (result == null)
return null;
return new Thing(outResult, result);
}
这个建议显然是错误的(我有单元测试 return 来自这个函数的非空值来证明这一点)!唯一可能是真的是 "DoSomething" 也总是 return 为 null,但它没有就此提出任何建议。
编辑:我已经通过完全重写 DoSomething 方法以不使用输出结果(而是 returns 包含 outResult 和结果的元组)解决了上述问题。但是我仍然有其他我想解决的错误警告,并且可能有相同的根本原因。
所以这实际上是两个问题:
- 我我做错了什么或遗漏了什么明显的东西吗?
- 假设 CC 只是 错误 我能做些什么来缓解将来的此类问题 - 至少隐藏警告!
Re: Contract.Ensures 关于 return 值
在您的 MVCE 和生产代码中,在 'burden of proof' 上游之后,问题几乎肯定与调用的 SelectScript
扩展方法(或 MVCE 中的 DoSomething
)有关,静态分析器推断(可能不正确)扩展方法总是 return 为 null,因此在调用方法 SelectSingle
中第一个分支(也 returning null)将总是被选中,因此推荐 null 的后置条件。
我找不到 SelectScript
的代码,但在 VS 2013 更新 4 / CC 1.7.11202.10 上,我只能通过显式 return 只从 SelectScript
并启用 "Infer ensures" 静态检查选项,或者通过显式添加 Contract.Ensures(Contract.Result<ScriptReference>() == null);
到 SelectScript
,例如with 确保推断:
public static ScriptReference SelectScript(
this IEnumerable<KeyValuePair<float, KeyValuePair<string, string>[]>> tags,
Func<double> random,
Func<KeyValuePair<string, string>[], Type[], ScriptReference> finder,
out KeyValuePair<string, string>[] selectedTags,
Type t)
{
selectedTags = null;
return null;
}
在调用方法中产生相同的警告 SelectSingle
:
CodeContracts: Consider adding the postcondition Contract.Ensures(Contract.Result() == null); to provide extra-documentation to the library clients
然而,对我来说,分析器似乎确实正确地推断出以下代码具有 return null 和 non-null 的分支,并且不建议调用者使用前提条件:
public static ScriptReference SelectScript(
this IEnumerable<KeyValuePair<float, KeyValuePair<string, string>[]>> tags,
Func<double> random,
Func<KeyValuePair<string, string>[], Type[], ScriptReference> finder,
out KeyValuePair<string, string>[] selectedTags,
Type t)
{
Contract.Requires(random != null);
selectedTags = null;
return (random() > 0.5)
? null
: new ScriptReference();
}
Re: Contract.Ensures关于out值
出于兴趣,也可以使用 Contract.ValueAtReturn
将合约添加到 out
参数 -
reference,第 2.2.3 页 p8.
例如如果您仍然在 out 参数上收到警告,您可以使用 grek40 的想法通过将此添加到 SelectScript
:
Contract.Ensures(Contract.ValueAtReturn(out selectedTags) == null ||
Contract.ValueAtReturn(out selectedTags) != null);