我最近安装了代码合同工具(.NET代码合同)和代码合同编辑器扩展VS2012,我在使静态检查器正常工作时遇到了一些麻烦。
当我在以下代码上运行Code Contracts的静态检查程序时(第二个假设被注释掉)
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.Contracts;
public class TestClass
{
public ReadOnlyCollection<byte> Foo()
{
Contract.Ensures(Contract.Result<ReadOnlyCollection<byte>>().Count == 4);
IList<byte> list = new byte[4];
Contract.Assume(list.Count == 4);
var returnValue = new ReadOnlyCollection<byte>(list);
//Contract.Assume(returnValue.Count == 4);
return returnValue;
}
}
我得到一个“确保未经证实”的警告:
CodeContracts:确保未经证实:
Contract.Result<ReadOnlyCollection<byte>>().Count == 4
它声称Foo
方法的确保未经证实。但是,当我将鼠标悬停在ReadOnlyCollection<T>
的{{3}}上时,我可以确定构造对象的Count
属性确保等于Count
属性{ {1}}参数:
也就是说,静态检查器应该能够告诉list
(即returnValue.Count == 4
的确保)成立。如果我取消注释第二个假设,警告确实会消失,但假设我的方法的确保非常正确,则会破坏静态检查器的目的。
我认为问题可能是只有编辑器扩展知道包含构造函数的确认的合同引用程序集(mscorlib.Contracts.dll),因此它列出了静态检查程序不知道的合同。
我尝试修改项目范围的额外合同图书馆路径设置无济于事,我认为这不是解决问题的正确方法。
我的理由是,我的理由是静态检查器没有正确配置合同参考组件,或者我错过了其他的东西?如果我是对的,我将如何修复配置?
我正在使用
编辑:静态检查器似乎确实找到了合同引用程序集,它的工作原理与我第一次预期的那样,它与其他类甚至Foo
类的方法一样。例如,静态分析以下方法就可以了。
ReadOnlyCollection<T>
关于 public int Boo()
{
Contract.Ensures(-1 <= Contract.Result<int>());
Contract.Ensures(Contract.Result<int>() < 4);
IList<byte> list = new byte[4];
var collection = new ReadOnlyCollection<byte>(list);
Contract.Assume(collection.Count == 4);
return collection.IndexOf(0);
}
属性的假设是必需的,因为构造函数的确保仍然不起作用。另一方面,Count
方法的确保效果非常好。
现在我想知道为什么静态检查器无法识别IndexOf
构造函数的确保。它可能是静态分析仪中的一个错误吗?
答案 0 :(得分:0)
代码合同可能会引发此警告,因为ReadOnlyCollection
类的Count属性不是常量。
在下面的示例中,我创建了ReadOnlyCollection
类的实例,传递包含4个整数的列表。 Count属性返回值4.我随后通过清除它并添加3个整数来修改ReadOnlyCollection
列表包裹。 ReadOnlyCollection
的Count属性现在返回值3,而我没有触及ReadOnlyCollection
。
IList<byte> list = new List<byte>() { 1, 2, 3, 4 };
var collection = new ReadOnlyCollection<byte>(list);
// Outputs: 1, 2, 3, 4.
foreach (var item in collection)
{
Console.WriteLine(item);
}
list.Clear();
list.Add(5);
list.Add(6);
list.Add(7);
// Outputs: 5, 6, 7
Console.WriteLine();
foreach (var item in collection)
{
Console.WriteLine(item);
}
Console.ReadKey();