| Clean Architecture Toolkit for .NET | |||||
|
Clean Architecture Toolkit is a clean, modular architecture foundation for .NET applications. It embraces SOLID principles and focuses on maintainability, testability, and scalability through clear boundaries and pluggable design. |
|
||||
|
| HOME | MODULE OVERVIEW | DEMO | |
|||||
Cat.Extensions
Cat.Extensions is a collection of small, focused extension method libraries. Each namespace targets one type, IEnumerable, Expression, IServiceCollection, string, or general objects, and has no dependency on any other CAT module, so you can pull in just the ones you need.
Table of contents
NuGet packages
| Package | Role | Install | Downloads |
|---|---|---|---|
| Cat.Enumerable.Extensions | Extensions | dotnet add package gmarginet.Cat.Enumerable.Extensions |
|
| Cat.Expression.Extensions | Extensions | dotnet add package gmarginet.Cat.Expression.Extensions |
|
| Cat.Object.Extensions | Extensions | dotnet add package gmarginet.Cat.Object.Extensions |
|
| Cat.ServiceCollection.Extensions | Extensions | dotnet add package gmarginet.Cat.ServiceCollection.Extensions |
|
| Cat.String.Extensions | Extensions | dotnet add package gmarginet.Cat.String.Extensions |
Namespaces
| Namespace | What it holds |
|---|---|
| Cat.Enumerable.Extensions | Extension methods for IEnumerable. |
| Cat.Expression.Extensions | Extension methods for expressions. |
| Cat.Object.Extensions | Extension methods for any object. |
| Cat.ServiceCollection.Extensions | Extension methods for IServiceCollection. |
| Cat.String.Extensions | Extension methods for strings. |
Dependencies
Cat.Extensions has no dependencies on other CAT modules.
Usage
Register the module
This module has nothing to register. Add a using for the namespace you need, and the extension methods show up on the type.
Enumerable
IsEmpty checks whether a sequence has any elements. It works on any IEnumerable, and it reads at most one element.
using Cat.Enumerable.Extensions;
if (items.IsEmpty()) return;
Expression
GetMemberInfo resolves the member a lambda expression points to. It returns null when the expression isn’t a direct member access on its parameter.
using Cat.Expression.Extensions;
Expression<Func<Order, int>> expression = order => order.Id;
MemberInfo? member = expression.GetMemberInfo(); // the Id property
Expression<Func<Order, string>> nested = order => order.Customer.Name;
MemberInfo? nestedMember = nested.GetMemberInfo(); // the Name property
Expression<Func<Order, int>> calculation = order => order.Id + 1;
MemberInfo? none = calculation.GetMemberInfo(); // null
Object
Validate arguments without hand-written null and range checks. Every method returns the value when it passes, so you can use it inline.
| Method | The value must be | Throws when |
|---|---|---|
ThrowIfNull |
Not null |
The value is null. |
ThrowIfLessThan |
At least the minimum | The value is less than the minimum. |
ThrowIfLessThanOrEqualTo |
Higher than the limit | The value is less than or equal to the limit. |
ThrowIfGreaterThan |
At most the maximum | The value is greater than the maximum. |
ThrowIfGreaterThanOrEqualTo |
Less than the limit | The value is greater than or equal to the limit. |
The four comparison methods use the default comparison of the type. Each also has an overload that takes your own IComparer<T>, placed right after the limit.
using Cat.Object.Extensions;
public Order(Customer customer, int quantity, int minQuantity, int maxQuantity)
{
_customer = customer.ThrowIfNull(nameof(customer));
_quantity = quantity.ThrowIfLessThan(1, nameof(quantity));
minQuantity.ThrowIfGreaterThanOrEqualTo(maxQuantity, nameof(minQuantity), nameof(maxQuantity));
}
ThrowIfLessThan, ThrowIfLessThanOrEqualTo and ThrowIfGreaterThan take the name of the parameter to report. ThrowIfGreaterThanOrEqualTo compares two values, so it takes the name of both.
With your own comparer:
_start = start.ThrowIfGreaterThanOrEqualTo(end, StringComparer.OrdinalIgnoreCase, nameof(start), nameof(end));
ServiceCollection
HasRegistrationFor checks whether a service is already registered. Use it to register something once, however many modules ask for it.
using Cat.ServiceCollection.Extensions;
if (services.HasRegistrationFor<ICatEventAggregator>()) return;
Pass a type when you only have it at runtime. An open generic type matches any registration for that generic definition:
var hasHandlers = services.HasRegistrationFor(typeof(ICatCommandHandler<>));
String
NamedFormat formats a named message template. The names are only for readability. Values are matched by position, in order.
using Cat.String.Extensions;
var message = "User {UserId} logged in at {Timestamp}".NamedFormat(userId, timestamp);
var padded = "Total: {Total,10:N2}".NamedFormat(total);
CreateRegex compiles a regular expression with a two-second matching timeout, so a pathological pattern can’t hang the caller.
var regex = @"^\d{3}-\d{4}$".CreateRegex();
var ignoreCase = @"^[a-z]+$".CreateRegex(RegexOptions.IgnoreCase);
Errors and exceptions
These methods throw exceptions. They don’t return responses.
| Method | Situation | What you get |
|---|---|---|
ThrowIfNull |
The argument is null |
An ArgumentNullException with the parameter name you passed. |
ThrowIfLessThan |
The value is less than the minimum | An ArgumentOutOfRangeException for the parameter you passed, with the actual value and the message <paramName> must be <minimum> or higher. |
ThrowIfLessThanOrEqualTo |
The value is less than or equal to the limit | An ArgumentOutOfRangeException for the parameter you passed, with the actual value and the message <paramName> must be higher than <limit>. |
ThrowIfGreaterThan |
The value is greater than the maximum | An ArgumentOutOfRangeException for the parameter you passed, with the actual value and the message <paramName> must be <maximum> or lower. |
ThrowIfGreaterThanOrEqualTo |
The value is greater than or equal to the limit | An ArgumentOutOfRangeException for the value name you passed, with the actual value and the message <valueName> must be less than <limitName>. |
| The four comparison methods without a comparer | T doesn’t implement IComparable<T> |
An ArgumentException with the message T is not IComparable<T>. |
CreateRegex |
The pattern isn’t a valid regular expression | An ArgumentException with the message Invalid regex expression: <pattern>. The original exception is the inner exception. |
NamedFormat |
There are fewer values than placeholders | A FormatException from string.Format. |
GetMemberInfo |
The expression isn’t a direct member access | null. No exception. |
IsEmpty, HasRegistrationFor |
Never | These don’t throw for valid input. |