技术开发 频道

.NET 4.0 中的契约式编程

  由于 .NET 要求显式实现接口方法,所以在契约内引用相同接口的其他方法就显得很笨拙。由此,.NET 允许在契约方法之前,使用一个局部变量引用接口类型。如下所示:

[ContractClassFor(typeof(IFoo))]
sealed class IFooContract : IFoo
{
    
int IFoo.Count
    {
        
get
        {
            Contract.Ensures(Contract.Result
<int>() >= 0);
            
return default(int);    // dummy return
        }
    }

    
void IFoo.Put(int value)
    {
        IFoo iFoo
= this;
        Contract.Requires(value
>= 0);
        Contract.Requires(iFoo.Count
< 10); // 否则的话,就需要强制转型 ((IFoo)this).Count
    }
}

 

  8. 抽象方法契约

  同接口类似,.NET 中抽象类中的抽象方法也不能包含方法体。所以同接口契约一样,需要帮助类来完成契约。代码示例不再给出。

  9. 契约方法重载

  所有的契约方法都有一个带有 string 类型参数的重载版本。如下所示:

Contract.Requires(obj != null, "if obj is null, then missiles are fired!");

  这样当契约被违反时,.NET 可以在运行时提供一个信息提示。目前,该字符串只能是编译时常量。但是,将来 .NET 可能会改变,字符串可以运行时被计算。但是,如果是字符串常量,静态诊断工具可以选择显示它。

  10. 契约特性

  A. ContractClass 和 ContractClassFor
  这两个特性,我们已经在接口契约和抽象方法契约里看到了。ContractClass 特性用于添加到接口或抽象类型上,但是指向的却是实现该类型的帮助类。ContractClassFor 特性用来添加到帮助类上,指向我们需要契约验证的接口或抽象类型。

  B. ContractInvariantMethod
  这个特性用来标记表示对象不变量的方法。

  C. Pure
  Pure 特性只声明在那些没有副作用的方法调用者上。.NET 现存的一些委托可以被认为如此,比如 System.Predicate<T> 和 System.Comparison<T>。

  D. RuntimeContracts
  这是个程序集级别的特性(具体如何,俺也不太清楚)。

  E. ContractPublicPropertyName
  这个特性用在字段上。它被用在方法契约中,且该方法相对于字段来说,更具可见性。比如私有字段和公共方法。如下所示:

[ContractPublicPropertyName("PublicProperty")]
private int field;
public int PublicProperty { get { ... } }

 

  F. ContractVerification
  这个特性用来假设程序集、类型、成员是否可被验证执行。我们可以使用 [ContractVerification(false)] 来显式标记程序集、类型、成员不被验证执行。

  .NET 契约库目前的缺陷
  接下来,讲一讲 .NET 契约库目前所存在的一些问题。

  值类型中的不变量是被忽略的,不发挥作用。
静态检测还不能处理 Contract.ForAll() 和 Contract.Exists() 方法。

  C# 迭代器中的契约问题。我们知道 Microsoft 在 C# 2.0 中添加了 yield 关键字来帮助我们完成迭代功能。它其实是 C# 编译器做的糖果。现在契约中,出现了问题。编译器产生的代码会把我们写的契约放入到 MoveNext() 方法中。这个时侯,静态检测就不能保证能够正确完成 Preconditions 契约。

0
相关文章