使用Contract.ValueAtReturn()的尴尬用途

时间:2010-05-06 10:46:46

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

我正在设计一个将元素添加到内部列表的方法。该类的结构类似于:

class MyCustomerDatabase {
    private IList<Customer> _customers = new List<Customer>();

    public int NumberOfCustomers { get { return _customers; } }    

    public void AddCustomer(Customer customer) {
        _customers.Add(customer);
    }
}

现在,我正在考虑添加一个Contract.Ensures(),大约相当于_customers增加1的大小。问题是我最终得到了一些奇怪的代码:

public void AddCustomer(Customer customer) {
    int numberOfCustomersAtReturn;
    Contract.Ensures(Contract.ValueAtReturn<int>(out numberOfCustomersAtReturn) == 
Contract.OldValue<int>(NumberOfCustomers) + 1);


    _customers.Add(customer);
    numberOfCustomersAtReturn = NumberOfCustomers;
}

主要问题是属性实际上是方法,因此在使用Contract.ValueAtReturn()时不能直接引用它们,因为它唯一的参数接受变量为out。 如果我想实现相同的情况,情况甚至更奇怪,但这次使用的方法应该返回一个值:

public int MyReturningMethod() {
    ...
   return abc(); //abc will add by one the number of customers in list
}
//gets converted to
public int MyReturningMethod() {
    int numberOfCustomersAtReturn;
    Contract.Ensures(Contract.ValueAtReturn<int>(out numberOfCustomersAtReturn) == Contract.OldValue<int>(NumberOfCustomers) + 1);

    int returnValue = abc();
    numberOfCustomersAtReturn = NumberOfCustomers;
    return returnValue;
}

这看起来很笨拙:(

代码合同应该旨在让事情变得更加清晰,而这恰恰相反。我做错了吗?

由于

2 个答案:

答案 0 :(得分:1)

我认为你做的一切都是正确的。

Altough我觉得你通过描述调用该方法的确切输出含义来将Contracts置于极端。 Imho合同的基本思想更多是为了确保 基本 保证,如积极的,完全返回一个值,等等。

答案 1 :(得分:1)

似乎你无缘无故地过度复杂化了。 ValueAtReturn用于向方法讨论out个参数,而不是其他内容 - 而且您没有任何out个参数!

您要找的是OldValue

假设这一行:

public int NumberOfCustomers { get { return _customers; } }   

意味着:

public int NumberOfCustomers { get { return _customers.Count; } }

您所要做的就是:

class MyCustomerDatabase
{
    private readonly IList<Customer> customers = new List<Customer>();

    public int NumberOfCustomers { get { return customers.Count; } }

    public void AddCustomer(Customer customer)
    {
        Contract.Ensures(NumberOfCustomers ==
                         Contract.OldValue(NumberOfCustomers) + 1);

        customers.Add(customer);
    }
}

静态检查器可以证明这很好,这要归功于IList<T>中的后置条件:)