我有一个这样开始的方法:
public static UnboundTag ResolveTag(Type bindingType, string name, string address)
{
Contract.Requires(bindingType != null);
var tags = GetUnboundTagsRecursively(bindingType).ToArray();
GetUnboundTagsRecursively 的实现(在同一个类中实现)的合约如下所示:
public static IEnumerable<UnboundTag> GetUnboundTagsRecursively(Type bindingType)
{
Contract.Requires(bindingType != null);
Contract.Ensures(Contract.Result<IEnumerable<UnboundTag>>() != null);
静态分析器通过消息指示 ResolveTag 的标签分配行出现故障"requires unproven: source != null"
。我已经看过好几次了,我不知道为什么会这样。我假设这是source
对扩展方法参数的引用ToArray()
。我的方法声明它确保结果不为空,所以这似乎意味着源ToArray()
也不为空。我错过了什么?
附加信息:返回 IEnumerable 的方法是通过 yield return 调用实现的。我想知道枚举器的魔法是否会以某种方式弄乱代码合同......
我只是尝试更改实现以返回一个空数组而不是使用 yield return 并通过合同,所以显然这是使用 yield return 的方法的问题。有人知道解决这个问题的方法吗?
我查看了 Contracts DLL 的 IL,它实际上将合约调用放入 MoveNext() 中以实现枚举器:
.method private hidebysig newslot virtual final
instance bool MoveNext() cil managed
{
.override [mscorlib]System.Collections.IEnumerator::MoveNext
// Code size 410 (0x19a)
.maxstack 3
.locals init ([0] bool V_0,
[1] int32 V_1)
.try
{
IL_0000: ldarg.0
IL_0001: ldfld int32 PLCLink.Bind.UnboundTag/'<GetUnboundTagsRecursively>d__c'::'<>1__state'
IL_0006: stloc.1
IL_0007: ldloc.1
IL_0008: ldc.i4.0
IL_0009: beq.s IL_0024
IL_000b: ldloc.1
IL_000c: ldc.i4.3
IL_000d: sub
IL_000e: switch (
IL_00cd,
IL_018d,
IL_0162)
IL_001f: br IL_018d
IL_0024: ldarg.0
IL_0025: ldc.i4.m1
IL_0026: stfld int32 PLCLink.Bind.UnboundTag/'<GetUnboundTagsRecursively>d__c'::'<>1__state'
IL_002b: ldarg.0
IL_002c: ldfld class PLCLink.Bind.IUnboundTagGroup PLCLink.Bind.UnboundTag/'<GetUnboundTagsRecursively>d__c'::group
IL_0031: ldnull
IL_0032: ceq
IL_0034: ldc.i4.0
IL_0035: ceq
IL_0037: call void [mscorlib]System.Diagnostics.Contracts.Contract::Requires(bool)
IL_003c: call !!0 [mscorlib]System.Diagnostics.Contracts.Contract::Result<class [mscorlib]System.Collections.Generic.IEnumerable`1<valuetype PLCLink.Bind.UnboundTag>>()
这很有趣,因为 Contract.Result 调用实际上使用了错误的类型(因为 MoveNext 返回一个布尔值)。