在引用另一种合同方法时是否应重复条件?

时间:2012-02-13 14:57:23

标签: .net c#-4.0 code-contracts

以下是接口合同的摘录。

我的问题是:前一种方法是否应重复后一种方法的前提条件?由于合同是公开的,省略重复是否可以接受?在这种情况下,它只是一个非空检查,但是我可以想象在运行时重复执行相同检查时会重复大量代码并且性能受损的情况。

public int CommandConsumerCount(IWriteCommand writeCommand)
{
    Contract.Requires(writeCommand != null); // redundant?
    Contract.Requires(this.IsOwnerOf(writeCommand));

    Contract.Ensures(Contract.Result<int>() >= 0);

    return default(int);
}

public bool IsOwnerOf(IWriteCommand writeCommand)
{
    Contract.Requires(writeCommand != null);

    return default(bool);
}

3 个答案:

答案 0 :(得分:2)

这取决于该条件(在这种情况下为writeCommand != null)是否是CommandConsumerCount方法和IsOwnerOf方法的要求,或者它是否只是IsOwnerOf方法的要求。

如果IsOwnerOf方法确实只需要这个条件,那么可以从CommandConsumerCount方法中省略它。

但是,如果这两种方法都需要这种条件,那么我将遵循下面的原始答案:

我认为,因为你的两种方法都是公开的,所以应该重复合同要求。如果您有一个私有方法执行实际工作,调用IsOwnerOf方法和CommandConsumerCount方法(而不是调用IsOwnerOf方法的CommandConsumerCount方法),那么可以省略对其内部的Contract.Requires的调用。私人方法。

就性能而言......除非检查本身的逻辑非常复杂,否则我不会担心这些检查对性能的影响。您可以设置编译器以从项目属性的“代码约定”部分中的编译输出中排除对Contract.Requires的调用(假设您已安装必要的插件)。

但也许我错过了你的问题。您是否在CommandConsumerCount方法中完全省略对IsOwnerOf的调用是否可以?在这种情况下,我会保留调用,但如果这是一个性能问题,那么我会配置项目以排除对Release版本的调用,假设我已经使用Debug构建进行了足够的测试以确保这个条件是满意。

编辑:在重新阅读问题之后,很明显你在询问writeCommand != null支票,所以我已经删除了上一段。

下面的代码示例,添加一个执行IsOwnerOf方法实际工作的私有方法。

    // you may want to choose a different name for this method
    private bool _IsOwnerOf(IWriteCommand)
    {
        // actual work is done here in this private method
        return default(bool);
    }

    public bool IsOwnerOf(IWriteCommand writeCommand)
    {
        Contract.Requires(writeCommand != null);

        // call the private method to perform the actual work
        return _IsOwnerOf(writeCommand);
    }

    public int CommandConsumerCount(IWriteCommand writeCommand)
    {
        Contract.Requires(writeCommand != null);
        Contract.Requires(_IsOwnerOf(writeCommand)); // call the private _IsOwnerOf method instead of the public method

        Contract.Ensures(Contract.Result<int>() >= 0);

        return default(int);
    }

答案 1 :(得分:2)

通常,如果方法A调用方法B,则A必须确保B上的所有合同都为真。

但是,如果在Requires中使用该方法,则它是多余的,因为所有Requires必须由方法的调用者证明。

例如,如果你有:

CommandConsumerCount(x);

如果没有关于x的信息,则静态检查器会抱怨IsOwnerOf必须为真。为了证明IsOwnerOf,您的代码必须执行以下操作:

if (IsOwnerOf(x))
{
    CommandConsumerCount(x);
}

或:

IWriteCommand GetWriteCommand()
{
    Contract.Ensures(IsOwnerOf(Contract.Result<IWriteCommand>()));

    //...
}

var x = GetWriteCommand();
CommandConsumerCount(x);

在这两种情况下,也会检查IsOwnerOf非空契约,因此证明该参数不为空。

但是,如果你有CommandConsumerCount这样的话:

int CommandConsumerCount(IWriteCommand command)
{
    Contract.Requires(command != null);

    if (IsOwnerOf(command))
    {
       // ...
    }

    return 0;
}

在这种情况下,CommandConsumerCount需要合同,因为调用者没有义务证明IsOwnerOf为真,因此不会检查非空合同。

答案 2 :(得分:1)

我想说每种方法都应该只指定它所需要的条件,并且不知道它所调用的条件方法。

因此,如果CommandConsumerCount需要writeCommand不为空,那么签订合同并不是多余的。

但是,如果CommandConsumerCount需要writeCommand不为空的唯一原因是将其传递给IsOwnerOf,那么它就是多余的。