契约式设计(Design By Contract DBC)规定方法应该对输入和输出进行验证,这样你便可以保证你得到的数据是可以工作的,一切都是按期望进行的,如果不是按期望进行,异常或是错误就应该被返回,要想了解DBC的更多信息请访问这里。
下面我们举的例子中,我们方法中的参数可能会为值为null的情况,在这种情况下由于我们没有验证,NullReferenceException异常会报出。另外在方法的结尾我们也没有保证会返回一个正确的decimal值给调用方法的对象。
1: public class CashRegister
2: {
3: public decimal TotalOrder(IEnumerable<Product> products, Customer customer)
4: {
5: decimal orderTotal = products.Sum(product => product.Price);
6:
7: customer.Balance += orderTotal;
8:
9: return orderTotal;
10: }
11: }
对上面的代码应用DBC是很简单的,首先我们断言我们不会有一个null值的customer对象,检查我们最少会有一个product对象。在返回订单总和之前先确保
我们会返回一个有意义的值。如果上面说的检查有任何一个失败,我们就抛出对应的异常,并在异常里说明错误的详细信息,而不是直接抛出
NullReferenceException。
在.NET Framework 3.5的Microsoft.Contracts命名空间下应该有一些DBC的类库方法,我还没有尝试过,但我想这应该是值得一看的,这里是我找到的惟一的资料。
1: public class CashRegister
2: {
3: public decimal TotalOrder(IEnumerable<Product> products, Customer customer)
4: {
5: if (customer == null)
6: throw new ArgumentNullException("customer", "Customer cannot be null");
7: if (products.Count() == 0)
8: throw new ArgumentException("Must have at least one product to total", "products");
9:
10: decimal orderTotal = products.Sum(product => product.Price);
11:
12: customer.Balance += orderTotal;
13:
14: if (orderTotal == 0)
15: throw new ArgumentOutOfRangeException("orderTotal", "Order Total should not be zero");
16:
17: return orderTotal;
18: }
19: }
上面的代码中添加了额外的代码来进行验证,但我认为这是非常值得做的,因为当NullReferenceException发生时去追查异常的详细信息真是很令人讨厌的。