C# Language
Кодовые контракты
Поиск…
Синтаксис
Contract.Requires (условие, userMessage)
Contract.Requires (условие, userMessage)
Contract.Result <Т>
Contract.Ensures ()
Contract.Invariants ()
замечания
.NET поддерживает идею Design by Contract через свой класс Contracts, найденный в пространстве имен System.Diagnostics и представленный в .NET 4.0. API Code Contracts API включает в себя классы для проверки статичности и времени выполнения кода и позволяет определять предварительные условия, постусловия и инварианты внутри метода. Предварительные условия определяют условия, которые должны выполнять параметры перед тем, как метод может выполнить, постусловия, которые проверяются по завершении метода, а инварианты определяют условия, которые не изменяются во время выполнения метода.
Зачем нужны кодовые контракты?
Отслеживание проблем приложения, когда приложение работает, является одной из главных проблем всех разработчиков и администраторов. Отслеживание может выполняться многими способами. Например -
Вы можете применить трассировку в нашем приложении и получить информацию о приложении, когда приложение запущено
Вы можете использовать механизм регистрации событий при запуске приложения. Сообщения можно увидеть с помощью средства просмотра событий
Вы можете применять мониторинг производительности через определенный промежуток времени и записывать данные в реальном времени из своего приложения.
Кодовые контракты используют другой подход для отслеживания и управления проблемами в приложении. Вместо того, чтобы проверять все, что возвращается из вызова метода, Кодовые контракты с помощью предварительных условий, постусловий и инвариантов в методах, убедитесь, что все входящие и выходящие из ваших методов правильны.
Предпосылками
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;
}
}
}
В приведенном выше коде мы определили интерфейс под названием IValidation
с атрибутом [ContractClass]
. Этот атрибут принимает адрес класса, в котором мы реализовали контракт для интерфейса. Класс ValidationContract
использует свойства, определенные в интерфейсе, и проверяет нулевые значения с использованием Contract.Requires<T>
. T
- класс исключения.
Мы также отметили get accessor с атрибутом [Pure]
. Чистый атрибут гарантирует, что метод или свойство не изменяет состояние экземпляра класса, в котором IValidation
интерфейс IValidation
.