У меня есть метод, который начинается так:Почему эти отношения с Кодексом не доказывают?
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, реализуется с обратными вызовами доходности. Мне интересно, возможно ли, что волшебник перечисления каким-то образом возится с кодовыми контрактами ...
Я просто попытался изменить реализацию, чтобы возвращать пустой массив, а не использовать возврат доходности и который передает контракты, так что, по-видимому, это проблема с метод с возвратом доходности. Кто-нибудь знает об этом?
Я посмотрел на 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 возвращает bool).
Я использую выпуск от 24 мая. Обертывание метода и использование предположения действительно работают, как вы подозревали. Он по-прежнему не может доказать «Гарантии» без «Предположения» (что неудивительно). На второстепенной стороне вашего примера кода отсутствует суффикс Impl в объявлении метода.Я взглянул на ИЛ и поставил это выше; ваша догадка была правильной, она попала в MoveNext(). –
@ Dan: Упс, спасибо - исправлен образец кода. –