CommunityToolkit / CommunityToolkit/dotnet
[Feature] Extend Guard Methods to Return Validated Arguments
- Dominant language
- C#
- Stars
- 3.8k
- Forks
- 400
- PR merge metrics
- No merged PRs in 30d
Description
# Proposal: Extend Guard Methods to Return Validated Arguments
# Summary
Extend the existing `Guard` functionality to provide an alternative version of all guard methods that return the validated argument when the validation passes. This enhancement would allow method chaining and inline validation assignments.
# Current Usage
The current `Guard` methods validate an argument and throw an exception if the validation fails, but they return `void`. This requires an extra assignment step when the argument is needed after validation.
## Example:
```
public class Processor
{
private readonly string _input;
public Processor(string input)
{
Guard.IsNotNullOrEmpty(input);
_input = input;
}
public void Print()
{
Console.WriteLine(_input);
}
}
```
# Proposed Enhancement
Provide an alternative version of all guard methods that return the validated argument when the validation passes. This would allow inline validation while preserving the original API behavior.
## Proposed Usage
Instead of requiring a separate assignment, the new API would allow:
```
public class Processor
{
private readonly string _input;
public Processor(string input)
{
_input = Guard.IsNotNullOrEmpty(input);
}
public void Print()
{
Console.WriteLine(_input);
}
}
```
# Implementation Options
Two approaches could be taken to introduce this feature:
## Option 1: Create a `ResultGuard` Class
Introduce a new `ResultGuard` class that mirrors `Guard` but returns the validated argument.
```
public static class ResultGuard
{
public static T IsNotNullOrEmpty(T value, [CallerArgumentExpression("value")] string? paramName = null)
where T : class
{
Guard.IsNotNullOrEmpty(value, paramName);
return value;
}
}
```
**Pros:**
- No changes to the existing `Guard` class.
-
- Clear separation between validation-only (`Guard`) and validation-with-return (`ResultGuard`).
**Cons:**
- Code duplication or the need to refactor `Guard` to reuse logic.
-
- Users must choose between `Guard` and `ResultGuard`.
## Option 2: Modify `Guard` to Return the Argument
Modify the existing `Guard` class to return the argument instead of `void`.
```
public static class Guard
{
public static T IsNotNullOrEmpty(T value, [CallerArgumentExpression("value")] string? paramName = null)
where T : class
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException($"{paramName} cannot be null or empty.", paramName);
}
return value;
}
}
```
**Pros:**
- No need for a new class.
-
- Maintains a single validation API.
-
- Fully backward-compatible since it only extends the return type.
**Cons:**
- Changes the return type of existing methods, which may have unforeseen consequences in certain use cases.
# Personal Preference
I personally prefer Option 2 (modifying `Guard`) because it avoids duplication, maintains backward compatibility, and enhances usability with minimal changes. However, I am open to other suggestions if the maintainers have concerns or alternative approaches in mind.
Would the maintainers be open to this enhancement? If so, I can submit a PR with the implementation.
Contributor guide
Assessment
This issue has not been assessed yet.