我有開始這樣的方法:爲什麼這個代碼合同關係證明不了?
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調用實現。我想知道如果也許統計數字魔法是搞亂代碼合同莫名其妙...
我只是試圖改變實現返回一個空數組,而不是使用收益率回報,並通過合同,所以顯然這是一個問題方法使用收益率回報。有人知道解決這個問題的方法嗎?
我接過一看IL的合同DLL,它實際上是把合同調用的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返回一個布爾值)。
我正在使用5月24日發佈。正如你懷疑的那樣,包裝方法和使用假設確實有效。它仍然無法證明沒有假設的保證(這並不令人驚訝)。在次要的方面,您的示例代碼缺少方法聲明中的Impl後綴。我看了一下IL,並把它放在上面;你的預感是正確的,它在MoveNext()中結束。 – 2010-06-23 17:36:48
@Dan:哎呀,謝謝 - 修正了示例代碼。 – 2010-06-23 19:06:38