代码合同:确保对代理的约束以避免"要求未经证实"警告?

时间:2014-12-31 00:03:58

标签: c# .net delegates code-contracts

我有一个类,它允许使用任何对象类型T的类似开关的语句,并允许指定返回类型R。当我尝试要求非空值时,我会收到警告requires unproven: value != null。想象一下,假设会带走静态检查器的警告但在运行时强制执行它,但它不会执行前者。我有什么选择?

这是包含Contract.Requires语句的类:

public class SwitchReturn<T, R>
{
    public SwitchReturn(T o)
    {
        Contract.Requires(o != null);

        Object = o;
    }

    public T Object { get; private set; }
    public bool HasValue { get; private set; }
    public R Value { get; private set; }

    public void Set(R value)
    {
        Contract.Requires(value != null); // <== the source of all the troubles

        Value = value;
        HasValue = true;
    }
}

以下是使用未经证实的要求调用代码的示例:

public static SwitchReturn<T, R> Case<T, R>(this SwitchReturn<T, R> s, Func<T, R> f)
{
    Contract.Requires(s != null);
    Contract.Requires(s.Object != null);
    Contract.Requires(f != null);

    if (!s.HasValue)
    {
        Contract.Assume(f(s.Object) != null); // <== does not remove the warning
        s.Set(f(s.Object)); // <== this is the cause of the warning
    }

    return s;
}

我不想删除非null要求。是否可以在FUNC参数上设置约束,确保它不返回空值?

2 个答案:

答案 0 :(得分:1)

f并不是纯粹的。调用它两次可能会得到不同的结果,所以假设第一个结果是非null,则说明第二个结果。

您应该能够将结果存储在变量中,添加关于该变量的假设,然后将其传递给您的其他方法。

if (!s.HasValue)
{
    var val = f(s.Object);
    Contract.Assume(val != null);
    s.Set(val);
}

答案 1 :(得分:0)

听起来问题的原因是TR可能是值类型。在这种情况下,空检查将失败。

解决方案是使用类型约束来要求TR作为引用类型。

public class SwitchReturn<T, R>
   where T : class
   where R : class
{
   ...
}