サーチ…
構文
Contract.Requires(Condition、userMessage)
Contract.Requires(Condition、userMessage)
Contract.Result <T>
Contract.Ensures()
Contract.Invariants()
備考
.NETは、System.Diagnostics名前空間にあるContractsクラスを使用してDesign by Contractアイデアをサポートし、.NET 4.0で導入されました。コードコントラクトAPIには、コードの静的チェックとランタイムチェックのクラスが含まれており、メソッド内の前提条件、事後条件、不変条件を定義することができます。前提条件は、メソッドが実行される前にパラメータが満たさなければならない条件、メソッドの完了時に検証される事後条件、メソッドの実行中に変化しない条件を不変条件で定義することを指定します。
コード契約が必要なのはなぜですか?
アプリケーションが実行されているときのアプリケーションの追跡に関する問題は、すべての開発者と管理者の最優先事項です。トラッキングは多くの方法で実行できます。例えば -
アプリケーションでトレースを適用し、アプリケーションの実行時にアプリケーションの詳細を取得することができます
アプリケーションの実行中は、イベントログ機能を使用できます。イベントビューアを使用してメッセージを表示できます
特定の時間間隔の後にPerformance Monitoringを適用し、アプリケーションからライブデータを書き込むことができます。
コードコントラクトは、アプリケーション内の問題の追跡と管理に異なるアプローチを使用します。前提条件、事後条件、およびメソッドの不変条件の助けを借りて、メソッド呼び出し、コード規約から返されたすべてを検証するのではなく、メソッドへの出入りがすべて正しいことを確認してください。
前提条件
namespace CodeContractsDemo
{
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
public class PaymentProcessor
{
private List<Payment> _payments = new List<Payment>();
public void Add(Payment payment)
{
Contract.Requires(payment != null);
Contract.Requires(!string.IsNullOrEmpty(payment.Name));
Contract.Requires(payment.Date <= DateTime.Now);
Contract.Requires(payment.Amount > 0);
this._payments.Add(payment);
}
}
}
事後条件
public double GetPaymentsTotal(string name)
{
Contract.Ensures(Contract.Result<double>() >= 0);
double total = 0.0;
foreach (var payment in this._payments) {
if (string.Equals(payment.Name, name)) {
total += payment.Amount;
}
}
return total;
}
不変量
namespace CodeContractsDemo
{
using System;
using System.Diagnostics.Contracts;
public class Point
{
public int X { get; set; }
public int Y { get; set; }
public Point()
{
}
public Point(int x, int y)
{
this.X = x;
this.Y = y;
}
public void Set(int x, int y)
{
this.X = x;
this.Y = y;
}
public void Test(int x, int y)
{
for (int dx = -x; dx <= x; dx++) {
this.X = dx;
Console.WriteLine("Current X = {0}", this.X);
}
for (int dy = -y; dy <= y; dy++) {
this.Y = dy;
Console.WriteLine("Current Y = {0}", this.Y);
}
Console.WriteLine("X = {0}", this.X);
Console.WriteLine("Y = {0}", this.Y);
}
[ContractInvariantMethod]
private void ValidateCoordinates()
{
Contract.Invariant(this.X >= 0);
Contract.Invariant(this.Y >= 0);
}
}
}
インタフェースでの契約の定義
[ContractClass(typeof(ValidationContract))]
interface IValidation
{
string CustomerID{get;set;}
string Password{get;set;}
}
[ContractClassFor(typeof(IValidation))]
sealed class ValidationContract:IValidation
{
string IValidation.CustomerID
{
[Pure]
get
{
return Contract.Result<string>();
}
set
{
Contract.Requires<ArgumentNullException>(!string.IsNullOrEmpty(value), "Customer ID cannot be null!!");
}
}
string IValidation.Password
{
[Pure]
get
{
return Contract.Result<string>();
}
set
{
Contract.Requires<ArgumentNullException>(!string.IsNullOrEmpty(value), "Password cannot be null!!");
}
}
}
class Validation:IValidation
{
public string GetCustomerPassword(string customerID)
{
Contract.Requires(!string.IsNullOrEmpty(customerID),"Customer ID cannot be Null");
Contract.Requires<ArgumentNullException>(!string.IsNullOrEmpty(customerID), "Exception!!");
Contract.Ensures(Contract.Result<string>() != null);
string password="AAA@1234";
if (customerID!=null)
{
return password;
}
else
{
return null;
}
}
private string m_custID, m_PWD;
public string CustomerID
{
get
{
return m_custID;
}
set
{
m_custID = value;
}
}
public string Password
{
get
{
return m_PWD;
}
set
{
m_PWD = value;
}
}
}
上のコードでは、 [ContractClass]
という属性を持つIValidation
というインターフェースを定義しました。この属性は、インタフェースのコントラクトを実装したクラスのアドレスを取ります。 ValidationContract
クラスは、インタフェースで定義されたプロパティを使用し、 Contract.Requires<T>
を使用してnull値をチェックします。 T
は例外クラスです。
getアクセサに[Pure]
属性を付けました。純粋な属性は、メソッドまたはプロパティがIValidation
インターフェイスが実装されているクラスのインスタンス状態を変更しないことを保証します。