Skip to main content

Getting Started

How the generator pipeline works

Step 1 — Mark your type as partial

The generator emits code into a second partial declaration alongside yours. Your type must be declared partial.

// Before
public class Money { ... }

// After
public partial class Money { ... }

Step 2 — Add [ValueObject]

using ZeroAlloc.ValueObjects;

[ValueObject]
public partial class Money
{
public decimal Amount { get; }
public string Currency { get; }

public Money(decimal amount, string currency)
{
Amount = amount;
Currency = currency;
}
}

Step 3 — Use it

var usd100 = new Money(100m, "USD");
var usd100b = new Money(100m, "USD");
var eur50 = new Money(50m, "EUR");

Console.WriteLine(usd100 == usd100b); // True
Console.WriteLine(usd100 == eur50); // False
Console.WriteLine(usd100.GetHashCode() == usd100b.GetHashCode()); // True

// Works as dictionary key, HashSet element, etc.
var prices = new Dictionary<Money, string>();
prices[usd100] = "one hundred dollars";
Console.WriteLine(prices[usd100b]); // "one hundred dollars"

What "zero allocation" means

The generated equality code uses only stack-local comparisons. For a two-property class:

// Generated — no heap allocations
public bool Equals(Money? other) =>
other is not null &&
Amount == other.Amount &&
Currency == other.Currency;

public override int GetHashCode() =>
System.HashCode.Combine(Amount, Currency);

There is no iterator, no boxing, no array creation. Every call is a direct property comparison.