ZeroAlloc.ValueObjects
1.1.4
dotnet add package ZeroAlloc.ValueObjects --version 1.1.4
NuGet\Install-Package ZeroAlloc.ValueObjects -Version 1.1.4
<PackageReference Include="ZeroAlloc.ValueObjects" Version="1.1.4" />
<PackageVersion Include="ZeroAlloc.ValueObjects" Version="1.1.4" />
<PackageReference Include="ZeroAlloc.ValueObjects" />
paket add ZeroAlloc.ValueObjects --version 1.1.4
#r "nuget: ZeroAlloc.ValueObjects, 1.1.4"
#:package ZeroAlloc.ValueObjects@1.1.4
#addin nuget:?package=ZeroAlloc.ValueObjects&version=1.1.4
#tool nuget:?package=ZeroAlloc.ValueObjects&version=1.1.4
ZeroAlloc.ValueObjects
Zero-allocation source-generated ValueObject equality for your existing domain types.
Same performance as record — without forcing the record keyword on your domain model. Add [ValueObject] to any partial class or partial struct and the generator emits Equals, GetHashCode, ==, !=, and ToString with no heap allocations.
Install
dotnet add package ZeroAlloc.ValueObjects
Quick start
// Annotate any existing partial class — no keyword changes, no base class
[ValueObject]
public partial class Money
{
public decimal Amount { get; }
public string Currency { get; }
public Money(decimal amount, string currency) => (Amount, Currency) = (amount, currency);
}
// Use standard equality — zero allocations
var a = new Money(10m, "USD");
var b = new Money(10m, "USD");
bool equal = a == b; // true
bool same = a.Equals(b); // true — IEquatable<Money> fast path
int hash = a.GetHashCode(); // same as b.GetHashCode() — safe as dict key
string s = a.ToString(); // "Money { Amount = 10, Currency = USD }"
Performance
ZeroAlloc.ValueObjects matches record and record struct performance exactly. The only allocating variant is CSharpFunctionalExtensions.ValueObject.
| Method | Mean | Allocated |
|---|---|---|
| CFE_Equals | 45.2 ns | 96 B |
| Record_Equals | 3.1 ns | 0 B |
| RecordStruct_Equals | 2.8 ns | 0 B |
| ZeroAlloc_Equals | 3.1 ns | 0 B |
| ZeroAllocStruct_Equals | 2.8 ns | 0 B |
| CFE_GetHashCode | 38.7 ns | 88 B |
| Record_GetHashCode | 2.4 ns | 0 B |
| RecordStruct_GetHashCode | 2.2 ns | 0 B |
| ZeroAlloc_GetHashCode | 2.4 ns | 0 B |
| ZeroAllocStruct_GetHashCode | 2.2 ns | 0 B |
Full methodology and more scenarios: docs/performance.md
Features
- Zero allocations — no iterator state machine, no boxing
- Works on existing
partial classandpartial struct— no refactoring required - Can inherit from non-record base classes
- Fine-grained member control with
[EqualityMember](opt-in) and[IgnoreEqualityMember](opt-out) - No extra generated members — no
with, noDeconstruct, noEqualityContract - Null-safe comparison for nullable reference type properties
HashCode.Combinefor ≤8 properties, incrementalHashCode.Addfor 9+
Why not just use record?
record |
ZeroAlloc.ValueObjects |
|
|---|---|---|
| Zero allocation | ✓ | ✓ |
Works on existing class/struct |
✗ — forces record keyword |
✓ |
| Can inherit from non-record base | ✗ | ✓ |
| Fine-grained member control | ✗ | [EqualityMember] / [IgnoreEqualityMember] |
| No extra generated members | ✗ — adds EqualityContract, with, deconstruct |
✓ |
| Struct support | record struct |
partial struct |
Documentation
| Page | Description |
|---|---|
| Why this library? | The problem with CFE, why not just use record |
| Installation | NuGet install, .NET version requirements |
| Getting Started | Step-by-step quickstart with core concepts |
| Attribute Reference | [ValueObject], [EqualityMember], [IgnoreEqualityMember] |
| Member Selection | How properties are chosen for equality |
| Generated Output | Exact code the generator emits |
| Struct vs. Class | When to use each, ForceClass |
| Nullable Properties | Null-safe comparison generation |
| Usage Patterns | Dictionary keys, HashSets, LINQ, EF Core, pattern matching |
| Migration Guide | From CFE ValueObject, from manual equality |
| Performance | Benchmark results and how to run them |
| Design Decisions | Trade-offs, intentional omissions |
| Troubleshooting | Common errors and fixes |
| Testing | Writing unit tests for value object equality |
| Examples | |
| E-Commerce | ProductId, Money, ShippingAddress, Discount |
| Finance | Iban, CurrencyPair, AccountNumber |
| HR / Identity | EmailAddress, EmployeeId, FullName |
| Geospatial | Coordinates, GeoRegion |
| Scheduling | DateRange, TimeSlot |
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.