CleanArch.DevKit.Guards 1.1.1

dotnet add package CleanArch.DevKit.Guards --version 1.1.1
                    
NuGet\Install-Package CleanArch.DevKit.Guards -Version 1.1.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CleanArch.DevKit.Guards" Version="1.1.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CleanArch.DevKit.Guards" Version="1.1.1" />
                    
Directory.Packages.props
<PackageReference Include="CleanArch.DevKit.Guards" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CleanArch.DevKit.Guards --version 1.1.1
                    
#r "nuget: CleanArch.DevKit.Guards, 1.1.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package CleanArch.DevKit.Guards@1.1.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CleanArch.DevKit.Guards&version=1.1.1
                    
Install as a Cake Addin
#tool nuget:?package=CleanArch.DevKit.Guards&version=1.1.1
                    
Install as a Cake Tool

CleanArch.DevKit.Guards

Static guard-clause utility for defensive argument validation in .NET 10. Returns the validated value for assignment chaining, captures parameter names automatically via [CallerArgumentExpression], throws only standard BCL exception types. No dependencies beyond the BCL.

Part of the CleanArch.DevKit set — standalone, no Mediator coupling.


Install

dotnet add package CleanArch.DevKit.Guards

Quick start

using CleanArch.DevKit.Guards;

public sealed class Order
{
    private readonly string _customerName;
    private readonly decimal _total;
    private readonly OrderStatus _status;

    public Order(string customerName, decimal total, OrderStatus status, IEnumerable<OrderLine> lines)
    {
        // Returns the value, so you can assign inline.
        _customerName = Guard.NotNullOrWhiteSpace(customerName);
        _total = Guard.NotNegative(total);
        _status = Guard.EnumDefined(status);

        // Throws if lines is null or has zero elements; iterates at most once.
        Guard.NotNullOrEmpty(lines);

        // Predicate guards take a value, an "is invalid" predicate, and a message.
        Guard.Against(lines, x => x.Count() > 100, "Order cannot exceed 100 lines.");
    }
}

Parameter names are captured automatically — you never write nameof(...):

public void Process(Order order)
{
    Guard.NotNull(order);
    // -> throws ArgumentNullException with ParamName = "order"
}

API reference

Method Throws Use case
NotNull<T>(T?) (class) ArgumentNullException Reject null reference arguments.
NotNull<T>(T?) (struct) ArgumentNullException Reject null Nullable<T>; returns the underlying value.
NotDefault<T>(T) ArgumentException Reject default(T) — e.g. Guid.Empty, DateTime.MinValue, 0.
NotNullOrEmpty(string?) ArgumentException Non-null, non-empty string (whitespace allowed).
NotNullOrWhiteSpace(string?) ArgumentException Non-null, non-empty, non-whitespace string.
NotNegative<T>(T) ArgumentOutOfRangeException T : INumber<T>, value ≥ 0.
NotNegativeOrZero<T>(T) ArgumentOutOfRangeException T : INumber<T>, value > 0.
NotZero<T>(T) ArgumentOutOfRangeException T : INumber<T>, value ≠ 0.
InRange<T>(T, min, max) ArgumentOutOfRangeException T : INumber<T>, value within inclusive [min, max].
GreaterThan<T>(T, other) ArgumentOutOfRangeException T : INumber<T>, value strictly greater than other.
LessThan<T>(T, other) ArgumentOutOfRangeException T : INumber<T>, value strictly less than other.
NotNullOrEmpty<T>(IEnumerable<T>?) ArgumentException Non-null, at least one element.
EnumDefined<T>(T) ArgumentOutOfRangeException T : struct, Enum, value is declared.
Against<T>(T, Func<T,bool>, string) ArgumentException Custom predicate — convention: true means invalid.

Note: NotNullOrEmpty(string?), NotNullOrWhiteSpace(string?), and NotNullOrEmpty<T>(IEnumerable<T>?) throw ArgumentException for both null and empty inputs — not ArgumentNullException for null. If you need to distinguish, use Guard.NotNull(...) first.

Every method returns the validated value, enabling field-init chaining:

public sealed class Money
{
    private readonly decimal _amount;
    public Money(decimal amount) => _amount = Guard.NotNegative(amount);
}

FAQ

Why no Result-based API? This package is for defensive validation at function entry. Result-based handling is for command/query layers — use CleanArch.DevKit.Mediator.Results with a ValidationBehavior for that. A Result-returning guard would mix two distinct responsibilities.

Why no extensibility hook? A hook (interface, partial class, extension methods) implies a contract this package would commit to. We don't yet know what that contract should look like and adding one prematurely locks us in. For domain-specific guards, write your own static class — it stays cohesive with your domain types and avoids a layering surprise.

Why no customMessage overloads on built-in guards? The standard messages are deliberate. If you need a different message, write throw new ArgumentException(...) directly — at that point the guard helper isn't buying you much. Against is the only guard that takes a message because its predicate is opaque to the helper.

Why no email/regex/URI guards? Format validation is too policy-specific (which RFC? which regex? case-sensitive?). Use System.Net.Mail.MailAddress or Uri.TryCreate directly — they're more accurate than any regex this package could ship.

Why INumber<T> rather than int / decimal overloads? One generic method covers every numeric BCL type (int, long, short, byte, decimal, double, float, Half, BigInteger, nint, nuint, and any custom type implementing INumber<T>). The JIT specializes per type, so performance matches type-specific overloads.


License

MIT. Copyright © 2026 Mickaël FRANCOIS.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.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.

Version Downloads Last Updated
1.1.1 89 5/17/2026
1.1.0 82 5/17/2026