Skip to main content
Version: 2.4.1

Guards & Validation

Overview

RCommon ships a Guard utility class that implements the guard clause pattern. Guard clauses validate inputs at the top of a method and throw a descriptive exception immediately when a precondition is violated, rather than allowing invalid state to propagate further into the call stack.

All methods are static, so no instantiation or dependency injection is required. You call them directly at the start of any method that needs to validate its arguments.

Installation

NuGet Package
dotnet add package RCommon.Core

No additional configuration is required. The Guard class is part of the RCommon namespace and is available as soon as the package is referenced.

Usage

Null checks

using RCommon;

public class OrderService
{
private readonly IOrderRepository _repository;

public OrderService(IOrderRepository repository)
{
Guard.IsNotNull(repository, nameof(repository));
_repository = repository;
}

public async Task SubmitOrder(Order order)
{
Guard.IsNotNull(order, nameof(order));
await _repository.SaveAsync(order);
}
}

Guard.IsNotNull throws ArgumentNullException when the argument is null.

String checks

public void SetCustomerName(string name)
{
Guard.IsNotEmpty(name, nameof(name)); // null, empty, or whitespace
Guard.IsNotOutOfLength(name, 100, nameof(name)); // max length
_name = name;
}

public void SetEmail(string email)
{
Guard.IsNotInvalidEmail(email, nameof(email));
_email = email;
}

public void SetWebsite(string url)
{
Guard.IsNotInvalidWebUrl(url, nameof(url));
_website = url;
}

GUID checks

public async Task<Order> GetOrder(Guid orderId)
{
Guard.IsNotEmpty(orderId, nameof(orderId));
return await _repository.GetByIdAsync(orderId);
}

Guard.IsNotEmpty(Guid, string) throws ArgumentException when the value is Guid.Empty.

An overload that returns a bool instead of throwing is also available when you prefer a conditional check:

if (!Guard.IsNotEmpty(orderId, nameof(orderId), throwException: false))
{
// handle the case gracefully
return null;
}

Numeric checks

public void SetPageSize(int pageSize)
{
Guard.IsNotNegative(pageSize, nameof(pageSize)); // < 0 throws
Guard.IsNotNegativeOrZero(pageSize, nameof(pageSize)); // <= 0 throws
}

public void SetDiscountRate(decimal rate)
{
Guard.IsNotNegative(rate, nameof(rate));
Guard.IsNotOutOfRange((int)rate, 0, 100, nameof(rate)); // range check (int only)
}

Numeric overloads exist for int, long, float, decimal, and TimeSpan.

Date checks

public void SetDeliveryDate(DateTime deliveryDate)
{
Guard.IsNotInvalidDate(deliveryDate, nameof(deliveryDate));
}

Collection checks

public void ProcessItems(ICollection<LineItem> items)
{
Guard.IsNotEmpty(items, nameof(items)); // null or Count == 0 throws
foreach (var item in items) { /* ... */ }
}

Arbitrary condition checks

Use Guard.Against<TException> when you need to assert a custom condition and throw a specific exception type:

Guard.Against<InvalidOperationException>(
_isLocked,
"Cannot modify a locked order.");

// Lambda overload — evaluated lazily
Guard.Against<InvalidOperationException>(
() => order.Status == OrderStatus.Cancelled,
"Cannot add items to a cancelled order.");

Type and interface checks

Guard.TypeOf<IPaymentProvider>(provider, "Provider must implement IPaymentProvider.");
Guard.Implements<IPaymentProvider>(providerType, "Type does not implement IPaymentProvider.");
Guard.InheritsFrom<BaseEntity>(entity, "Entity must inherit from BaseEntity.");

Equality checks

Guard.IsEqual<ArgumentException>(expectedVersion, actualVersion,
"Version mismatch — optimistic concurrency violation.");

API Summary

MethodThrowsCondition
IsNotNull(object, string)ArgumentNullExceptionArgument is null
IsNotEmpty(string, string)ArgumentExceptionString is null, empty, or whitespace
IsNotEmpty(string, string, bool)ArgumentException or falseString is null, empty, or whitespace
IsNotOutOfLength(string, int, string)ArgumentExceptionString length exceeds maximum
IsNotInvalidEmail(string, string)ArgumentExceptionString is not a valid email address
IsNotInvalidWebUrl(string, string)ArgumentExceptionString is not a valid web URL
IsNotEmpty(Guid, string)ArgumentExceptionGUID is Guid.Empty
IsNotEmpty(Guid, string, bool)ArgumentException or falseGUID is Guid.Empty
IsNotEmpty<T>(ICollection<T>, string)ArgumentExceptionCollection is null or empty
IsNotNegative(int/long/float/decimal/TimeSpan, string)ArgumentOutOfRangeExceptionValue is less than zero
IsNotNegativeOrZero(int/long/float/decimal/TimeSpan, string)ArgumentOutOfRangeExceptionValue is zero or less
IsNotOutOfRange(int, int, int, string)ArgumentOutOfRangeExceptionValue is outside [min, max]
IsNotInvalidDate(DateTime, string)ArgumentOutOfRangeExceptionDate is not valid
Against<TException>(bool, string)TExceptionAssertion is true
Against<TException>(Func<bool>, string)TExceptionLambda returns true
TypeOf<TType>(object, string)InvalidOperationExceptionObject is not of expected type
Implements<TInterface>(object/Type, string)InvalidOperationExceptionType does not implement interface
InheritsFrom<TBase>(object/Type, string)InvalidOperationExceptionType does not inherit from base
IsEqual<TException>(object, object, string)TExceptionObjects are not equal
RCommonRCommon