C# 代码契约-ForAll-静态验证支持什么
有大量信息表明,C# 代码契约-ForAll-静态验证支持什么,c#,static-analysis,code-contracts,C#,Static Analysis,Code Contracts,有大量信息表明,契约的静态检查。对于所有来说,支持的范围有限或没有 我做了很多实验,发现它可以与一起工作: Contract.ForAll(items,i=>i!=null) Contract.ForAll(items,p)其中p属于谓词类型 它不能与以下各项一起工作: 现场访问 财产访问权 方法组(我认为无论如何都在这里分配了委托) 实例方法调用 我的问题是: ForAll还可以使用哪些类型的代码 在Contract.ForAll(items,i=>i!=null)被证明从代码后面的
契约的静态检查。对于所有
来说,支持的范围有限或没有
我做了很多实验,发现它可以与一起工作:
Contract.ForAll(items,i=>i!=null)
其中Contract.ForAll(items,p)
属于p
谓词类型
- 现场访问
- 财产访问权
- 方法组(我认为无论如何都在这里分配了委托)
- 实例方法调用
还可以使用哪些类型的代码ForAll
- 在
Contract.ForAll(items,i=>i!=null)
被证明从代码后面的列表中获取一项时(即通过索引),该项不为null之后,代码是否会收缩
public sealed class Test
{
public bool Field;
public static Predicate<Test> Predicate;
[Pure]
public bool Property
{
get { return Field; }
}
[Pure]
public static bool Method(Test t)
{
return t.Field;
}
[Pure]
public bool InstanceMethod()
{
return Field;
}
public static void Test1()
{
var items = new List<Test>();
Contract.Assume(Contract.ForAll(items, i => i != null));
Contract.Assert(Contract.ForAll(items, i => i != null)); // OK
}
public static void Test2()
{
var items = new List<Test>();
Contract.Assume(Contract.ForAll(items, Predicate));
Contract.Assert(Contract.ForAll(items, Predicate)); // OK
}
public static void Test3()
{
var items = new List<Test>();
Contract.Assume(Contract.ForAll(items, i => i.Field));
Contract.Assert(Contract.ForAll(items, i => i.Field)); // assert unproven
}
public static void Test4()
{
var items = new List<Test>();
Contract.Assume(Contract.ForAll(items, i => i.Property));
Contract.Assert(Contract.ForAll(items, i => i.Property)); // assert unproven
}
public static void Test5()
{
var items = new List<Test>();
Contract.Assume(Contract.ForAll(items, Method));
Contract.Assert(Contract.ForAll(items, Method)); // assert unproven
}
public static void Test6()
{
var items = new List<Test>();
Contract.Assume(Contract.ForAll(items, i => i.InstanceMethod()));
Contract.Assert(Contract.ForAll(items, i => i.InstanceMethod()));// assert unproven
}
}
公共密封类测试
{
公共领域;
公共静态谓词;
[纯]
公共布尔财产
{
获取{返回字段;}
}
[纯]
公共静态布尔法(试验t)
{
返回t.字段;
}
[纯]
公共布尔实例方法()
{
返回字段;
}
公共静态void Test1()
{
var items=新列表();
假设(Contract.ForAll(items,i=>i!=null));
Assert(Contract.ForAll(items,i=>i!=null));//确定
}
公共静态void Test2()
{
var items=新列表();
契约。假设(契约。所有(项目,谓词));
Contract.Assert(Contract.ForAll(items,Predicate));//确定
}
公共静态void Test3()
{
var items=新列表();
假设(Contract.ForAll(items,i=>i.Field));
Assert(Contract.ForAll(items,i=>i.Field));//Assert unproven
}
公共静态void Test4()
{
var items=新列表();
假设(Contract.ForAll(items,i=>i.Property));
Assert(Contract.ForAll(items,i=>i.Property));//Assert unproven
}
公共静态void Test5()
{
var items=新列表();
合同。假设(合同。所有(项目、方法));
Contract.Assert(Contract.ForAll(items,Method));//Assert unproven
}
公共静态void Test6()
{
var items=新列表();
Contract.aspect(Contract.ForAll(items,i=>i.InstanceMethod());
Contract.Assert(Contract.ForAll(items,i=>i.InstanceMethod());//Assert未经验证
}
}
通过反编译mscorelib.dllSystem.Diagnostics.Contracts
我们可以轻松地看到Contract.ForAll是如何构建的:它需要集合和谓词
public static bool ForAll<T>(IEnumerable<T> collection, Predicate<T> predicate)
{
if (collection == null)
{
throw new ArgumentNullException("collection");
}
if (predicate == null)
{
throw new ArgumentNullException("predicate");
}
foreach (T current in collection)
{
if (!predicate(current))
{
return false;
}
}
return true;
}
publicstaticboolforall(IEnumerable集合,谓词)
{
if(集合==null)
{
抛出新的ArgumentNullException(“集合”);
}
if(谓词==null)
{
抛出新的ArgumentNullException(“谓词”);
}
foreach(集合中的T当前值)
{
if(!谓词(当前))
{
返回false;
}
}
返回true;
}
所以当你说Contract.ForAll(items,i=>i.Field)
在这个例子中,i=>i.Field
是谓词
然后,通过在所有测试方法中遵循您的示例,我们可以看到您为Contract.ForAll
方法提供了一个空列表,该列表将返回true,因为它永远不会进入foreach块
更进一步说,如果您将项目添加到列表中
var items=newlist(){newtest()}
并再次运行测试,它将返回false作为公共bool字段代码>默认为false
总的来说,合同的目标是
确定集合中的所有元素是否存在于
作用
因此,我的结论是,这与Contarct无关。ForAll不能处理某些内容,而是集合中至少有一个元素返回false或为null我无法找到更多的工作表达式,事实上,我发现即使是Contract.ForAll(items,I=>I!=null)
也不能可靠地工作(但它知道,当后来在同一个函数中的foreach内部使用该项时,该项不是空的)。最后,我放弃了使用更复杂的ForAll contracts和static checker的可能性
相反,我设计了一种方法来控制哪些契约用于静态检查器,哪些契约用于运行时检查器。我在这里介绍了这种方法,希望它可能对对对原始问题感兴趣的人有用。好处是能够编写更复杂的契约,这些契约只能在运行时进行检查,并且只留下易于证明的契约用于静态检查器的RACT(并轻松保持低计数的警告)
为此,需要2个调试版本(如果您还没有),调试和调试+静态契约,调试生成有条件编译符号MYPROJECT\u Contracts\u RUNTIME定义。这样,它将接收所有契约。
和RtContract。
契约。其他生成只接收契约。
契约
public static class RtContract
{
[Pure] [ContractAbbreviator] [Conditional("MYPROJECT_CONTRACTS_RUNTIME")]
public static void Requires(bool condition)
{
Contract.Requires(condition);
}
[Pure] [ContractAbbreviator] [Conditional("MYPROJECT_CONTRACTS_RUNTIME")]
public static void Ensures(bool condition)
{
Contract.Ensures(condition);
}
[Pure] [Conditional("MYPROJECT_CONTRACTS_RUNTIME")]
public static void Assume(bool condition)
{
Contract.Assume(condition);
}
}
public class Usage
{
void Test (int x)
{
Contract.Requires(x >= 0); // for static and runtime
RtContract.Requires(x.IsFibonacci()); // for runtime only
}
}
感谢您的努力,但我的问题是关于代码契约引擎进行静态分析的能力。这与ForAll函数的代码中实现的运行时特征无关。