Why SGuard?
Discover what makes SGuard a powerful choice for guard clauses in .NET.
Clear Diagnostics
Uses CallerArgumentExpression to produce precise, helpful error messages that point to the exact argument/expression that failed.
ThrowIf.NullOrEmpty(user.Email);
// NullOrEmptyException: Value 'user.Email' is null or empty.
// ex.ParamName == "user.Email"
No more manual message crafting—SGuard does it for you. Built-in exceptions derive from ArgumentException, and checked values are left out of messages unless you set SGuardOptions.IncludeValuesInExceptions = true.
Consistent Callback Model
A single SGuardCallback(outcome) works across both APIs:
ThrowIf.*invokes withFailurewhen it's about to throw,Successwhen it passes.Is.*invokes withSuccesswhen the result is true,Failurewhen false (the method's result, not "validation passed").
Callback exceptions are safely swallowed, so your validation flow isn't disrupted.
ThrowIf.LessThan(1, 2, SGuardCallbacks.OnFailure(() =>
logger.LogWarning("Validation failed")));
bool ok = Is.Between(5, 1, 10, SGuardCallbacks.OnSuccess(() =>
metrics.Increment("validation.success")));
Rich Exception Surface
Throw built-in exceptions for common guards or supply your own:
- Pass a custom exception instance
- Use a generic
TException - Provide constructor arguments for detailed messages
ThrowIf.LessThanOrEqual(quantity, 0,
new DomainValidationException("Quantity must be greater than zero."));
Expressive, Dual API
Choose the style that fits your code:
Is.*returns booleans for control-flow friendly checksThrowIf.*fails fast with informative exceptions when rules are violated
Both share the same underlying logic and performance characteristics.
Culture-Aware Comparisons
The string overloads of the Is.* comparisons and ThrowIf.Between accept StringComparison for correct cultural/ordinal semantics.
bool ordinal = Is.LessThan("apple", "Banana", StringComparison.Ordinal); // false ('a' > 'B' by code point)
bool culture = Is.LessThan("apple", "Banana", StringComparison.InvariantCulture); // true
ThrowIf.Between("kiwi", "a", "m", StringComparison.OrdinalIgnoreCase); // throws: "kiwi" is inside the range
Between checks are inclusive by design for predictable validation.
Performance and Ergonomics
- Expression caching: selector expressions are compiled once and cached by expression structure in a thread-safe cache (including selectors that capture local variables or use operators such as
+and??) - No work when you don't need it: plain comparisons and null/empty checks without a selector don't compile expressions
- Allocation-free guards: a passing guard costs about as much as a hand-written
ifand allocates nothing - Custom exception types are created only when the guard fails: with
new TException()for thenew()overloads, and through reflection forconstructorArgs
See Performance for benchmarks and details.
Modern .NET Support
Targets .NET 8, 9, and 10 with multi-targeting.
Next Steps
- Core Concepts - Dive deeper into guard methods
- Callbacks - Learn about the callback model
- Performance - See benchmarks and optimization tips