Guardian

Lightweight, high-performance library providing guard clauses for validating method parameters and ensuring defensive programming practices in .NET applications.

109
Unit Tests
90%+
Code Coverage
Zero
Dependencies
25+
Guard Methods

Why Choose Guardian?

Built specifically for defensive programming with performance and developer experience in mind.

Performance Optimized

Minimal overhead with inline methods and zero allocations for successful validations. Built for production workloads.

Type Safe

Full support for generics and nullable reference types with compile-time safety and IntelliSense support.

Modern C# Features

Uses CallerArgumentExpression for automatic parameter name capture and supports the latest .NET versions.

Get Started in 2 Minutes

Install Guardian and start writing defensive code immediately.

1. Installation

$ dotnet add package Guardian

Or via Package Manager Console:

Install-Package Guardian

2. Add Using Statement

using Guardian;

3. Start Using Guards

Guard.Against.Null(user);
Product.cs
using Guardian;

public class Product
{
    public string Name { get; }
    public decimal Price { get; }
    public int StockQuantity { get; }

    public Product(string name, decimal price, int stockQuantity)
    {
        Name = Guard.Against.NullOrWhiteSpace(name);
        Price = Guard.Against.NegativeOrZero(price);
        StockQuantity = Guard.Against.Negative(stockQuantity);
    }
}

Available Guard Clauses

Comprehensive validation methods for all common scenarios and edge cases.

Guard.Against.Null()

Throws if value is null

Guard.Against.Null(user)

Guard.Against.NullOrEmpty()

Throws if string/collection is null or empty

Guard.Against.NullOrEmpty(name)

Guard.Against.NullOrWhiteSpace()

Throws if string is null, empty, or whitespace

Guard.Against.NullOrWhiteSpace(email)

Guard.Against.Default()

Throws if value equals default(T)

Guard.Against.Default(orderId)

Guard.Against.Negative()

Throws if value is negative

Guard.Against.Negative(quantity)

Guard.Against.Zero()

Throws if value is zero

Guard.Against.Zero(divisor)

Guard.Against.NegativeOrZero()

Throws if value is negative or zero

Guard.Against.NegativeOrZero(price)

Guard.Against.OutOfRange()

Throws if value is outside specified range

Guard.Against.OutOfRange(age, 1, 120)

Guard.Against.GreaterThan()

Throws if value exceeds maximum

Guard.Against.GreaterThan(score, 100)

Guard.Against.LessThan()

Throws if value is below minimum

Guard.Against.LessThan(temperature, 0)

Guard.Against.InvalidFormat()

Throws if string doesn't match regex pattern

Guard.Against.InvalidFormat(email, @"^[^@\s]+@[^@\s]+\.[^@\s]+$")

Guard.Against.InvalidLength()

Throws if string length is outside range

Guard.Against.InvalidLength(password, 8, 100)

Guard.Against.NullOrEmpty()

Throws if collection is null or empty

Guard.Against.NullOrEmpty(items)

Guard.Against.NotInEnum()

Throws if value is not a defined enum value

Guard.Against.NotInEnum(status)

Guard.Against.Condition()

Throws if custom condition is false

Guard.Against.Condition(balance >= amount)

Guard.Against.NotOneOf()

Throws if value is not in allowed list

Guard.Against.NotOneOf(currency, validCurrencies)

Real-World Examples

See Guardian in action with practical examples from common development scenarios.

Constructor Validation

Validate constructor parameters to ensure objects are created in a valid state from the start.

Fail fast at object creation
Clear parameter validation
Immutable object guarantee
public class Customer
{
    public Guid Id { get; }
    public string Name { get; }
    public int Age { get; }
    public string Email { get; }

    public Customer(Guid id, string name, int age, string email)
    {
        Id = Guard.Against.Default(id);
        Name = Guard.Against.InvalidLength(name, 2, 100);
        Age = Guard.Against.OutOfRange(age, 18, 120);
        Email = Guard.Against.InvalidFormat(email, 
            @"^[^@\s]+@[^@\s]+\.[^@\s]+$");
    }
}

Method Parameter Validation

Validate method parameters at the entry point to prevent invalid operations and provide clear error messages.

Early parameter validation
Multiple guard combinations
Business rule validation
public void ProcessOrder(Guid orderId, string customerEmail, 
                         decimal amount, List<Item> items)
{
    // Basic validation
    Guard.Against.Default(orderId);
    Guard.Against.InvalidFormat(customerEmail, 
        @"^[^@\s]+@[^@\s]+\.[^@\s]+$");
    Guard.Against.OutOfRange(amount, 0.01m, 10000m);
    Guard.Against.NullOrEmpty(items);
    
    // Business rule validation
    var totalItemValue = items.Sum(i => i.Price);
    Guard.Against.Condition(totalItemValue == amount,
        nameof(amount), "Amount must match total item value");
    
    // Process the order...
}

Business Logic Validation

Use custom conditions to validate complex business rules and domain-specific constraints.

Domain-specific validation
Custom error messages
Complex condition checking
public void TransferFunds(decimal amount, Account fromAccount, 
                        Account toAccount)
{
    Guard.Against.NegativeOrZero(amount);
    Guard.Against.Null(fromAccount);
    Guard.Against.Null(toAccount);
    
    // Business rule: Sufficient funds
    Guard.Against.Condition(
        fromAccount.Balance >= amount,
        nameof(amount),
        $"Insufficient funds. Available: {fromAccount.Balance}, Requested: {amount}"
    );
    
    // Business rule: Different accounts
    Guard.Against.Condition(
        fromAccount.Id != toAccount.Id,
        nameof(toAccount),
        "Cannot transfer to the same account"
    );
    
    // Business rule: Account status
    Guard.Against.Condition(
        fromAccount.Status == AccountStatus.Active &&
        toAccount.Status == AccountStatus.Active,
        nameof(fromAccount),
        "Both accounts must be active"
    );
    
    // Perform transfer...
}

Best Practices

Follow these guidelines to get the most out of Guardian in your applications.

Do's

Use at Method Entry Points

Place guards at the beginning of methods to fail fast and provide clear error messages.

Be Specific

Use the most specific guard clause available for better error messages and clearer intent.

Provide Custom Messages

Add custom error messages for domain-specific validations to help with debugging.

Combine Multiple Guards

Use multiple guard clauses together for comprehensive parameter validation.

Apply Consistently

Use guards consistently across your codebase for predictable behavior.

Don'ts

Don't Overuse in Hot Paths

Avoid excessive guards in performance-critical loops where validation has already occurred.

Don't Replace Domain Logic

Guards are for parameter validation, not complex business rule enforcement.

Don't Ignore Return Values

Always use the return value from guard methods as they may modify the input.

Don't Use Generic Exceptions

Let Guardian throw appropriate exception types rather than catching and re-throwing.

Don't Skip Documentation

Document complex guard conditions to help other developers understand the constraints.

Performance Optimized

Guardian is designed for minimal performance impact in production applications.

Zero Allocations

No memory allocations when validation passes

Inline Optimization

Methods optimized for JIT compilation

Generic Constraints

Prevents boxing of value types

Success Path Optimized

Fast execution when validation succeeds

Framework Support

Guardian supports all modern .NET platforms and framework versions.

.NET 6.0, 7.0, 8.0

Full support for latest .NET versions

.NET Standard 2.0/2.1

Compatibility with .NET Framework 4.6.1+

Modern C# Features

CallerArgumentExpression and nullable references

Zero Dependencies

No external package dependencies

<PackageReference Include="Guardian" Version="1.0.0" />

Ready to Write Defensive Code?

Start using Guardian today and make your .NET applications more robust with comprehensive parameter validation.