在Func <t>参数上指定代码合约?</t>

时间:2010-10-30 18:44:32

标签: c# lambda code-contracts

说我有以下

public T Example(Func<T> f)
{
     Contract.Requires(f != null);
     Contract.Requires(f() != null); // no surprise, this is an error
...
}

有没有办法指定我的Func<T>参数必须遵守某些合同?

3 个答案:

答案 0 :(得分:2)

一般来说,这似乎是一个有问题的要求,因为调用f可能会引入副作用,因此指定合同可能会影响方法的作用。

作为Code Contracts库的实现者,可以引入包装器代码,该代码检查f的值是否在方法的上下文中调用时遵守合同(以避免引入虚假方法调用) )。出于以下几个原因,这是有问题的:

  1. 该方法可能永远不会调用f,因此调用方可能违反合同而不会被破坏。
  2. 只有在对f的调用不符合规范的情况下执行其他可能无效的工作后,该方法才能调用f
  3. 如果f没有副作用,那么这些就不会出现问题,但是如果总是调用f来处理1的副作用会出现问题,那么就会调用f在做任何处理2的工作之前也不会飞。

    因此,总而言之,我认为这不可能(在本机代码合同的背景下)并且有充分的理由。

答案 1 :(得分:1)

如果您的意思是传递的方法应检查自己是否例如参数不为null,不能你不能这样做。合同仍然只是将代码添加到方法体。

您可以做的是将委托包装到不同的委托中,例如:

public T Example<T, TResult>(Func<T, TResult> f)
    where T : class
    where TResult : class
{
    Contract.Requires(f != null);

    f = WrapWithContracts(f);

    // ...
}

private Func<T, TResult> WrapWithContracts<T, TResult>(Func<T, TResult> f)
    where T : class
    where TResult : class
{
    return p =>
    {
        Contract.Requires(p != null);
        Contract.Ensures(Contract.Result<TResult>() != null);

        var result = f(p);

        return result;
    };
}

这样您就可以自己引入代码合同。

答案 2 :(得分:0)

如果(如此处)它是您所关注的特定无效,ReSharper(从4.0开始)支持注释,例如CanBeNullNotNull,可以作为方法的属性放置,之后R#可以警告可能的空解除引用操作。