Skip to main content

Pledge

Pledge is Design by Contract for .NET 10 and later. You write preconditions, postconditions and Old() snapshots as ordinary C# at the top of a method, and a Roslyn source generator checks them at build time through C# interceptors. There is no IL rewriter, no compiler fork and no IDE extension.

Alpha

Pledge is at 0.1.0-alpha. The API can still change between pre-releases.

Install​

dotnet add package Pledge --prerelease

That is the whole setup. The package carries the runtime, the generator, the analyzers with their code fixes, and the build targets that turn on the interceptors feature for your project.

Write a contract​

using PledgeContracts;

public sealed class Account(decimal balance)
{
public decimal Balance { get; private set; } = balance;

public decimal Withdraw(decimal amount)
{
Pledge.Requires(amount > 0);
Pledge.Requires(amount <= Balance, "insufficient funds");
Pledge.Ensures(Balance == Pledge.Old(Balance) - amount);
Pledge.Ensures(Pledge.Result<decimal>() >= 0);

Balance -= amount;
return Balance;
}
}

The Pledge.* lines compile to nothing inside the method. Instead, every call to Withdraw in your project is replaced at build time with a call that checks the contracts around it.

Break it​

var account = new Account(100m);
account.Withdraw(250m);

In a Debug build this throws PreconditionViolationException, and the message names the contract, the member and the caller:

Precondition of Account.Withdraw violated by its caller: insufficient funds [amount <= Balance] (at /src/Program.cs:9)

A broken precondition is the caller's fault; a broken postcondition is the method's. In a Release build the checks are off by default and the assembly is the one you would get without Pledge. See enforcement modes to change that.

Next​