.NET 6, 7 and 8 introduced a set of powerful Argument...Exception.ThrowIf... helper methods. They’re fast, they’re clean, and they eliminate a ton of repetitive guard‑clause code. But let’s be honest: writing validation logic in every property setter still gets old quickly.
So I built ReflectionIT.PropertyThrowGenerator — a Roslyn source generator that injects validation logic directly into your partial properties using simple [ThrowIf...] attributes. You declare what should be validated, and the generator writes the how.
No more boilerplate. No more forgetting a null check. No more copy‑paste errors.
Just clean, validated properties.
Why I built it
I love the clarity of the new ThrowIf... APIs, but I wanted a way to apply them declaratively. Attributes are perfect for this: they’re readable, discoverable, and self‑documenting.
With this generator, you can express intent like:
- “This property must not be null.”
- “This number must be positive.”
- “This value must be less than X.”
- “This string must not be empty or whitespace.”
…and the generator emits the correct setter logic automatically.
How it works
- Install the NuGet package.
- Add one or more
[ThrowIf...]attributes to a partial property. - The generator emits the implementation part of the property, inserting the correct validation calls before assigning the backing field.
If you accidentally apply a ThrowIf attribute to a non‑partial property, the analyzer will warn you immediately (PTG002) .
Because the generator uses the new field keyword and the .NET 8 throw helpers, your project must target:
- C# 14.0 or higher
- .NET 8.0 or higher
A simple example
using ReflectionIT.PropertyThrowGenerator.Attributes;
partial class Employee
{
[ThrowIfNull]
public required partial string Name { get; set; }
[ThrowIfNull]
[ThrowIfGreaterThan("London")]
public partial string City { get; set; } = string.Empty;
[ThrowIfLessThanOrEqual(17)]
public partial int Age { get; set; }
[ThrowIfGreaterThan("1234.56M")]
[ThrowIfNegative]
public partial decimal Salary { get; set; }
}
This generates a fully validated implementation:
- Null checks for
NameandCity - Range checks for
AgeandSalary - Multiple validators applied in order
- Automatic use of the correct
Argument...Exception.ThrowIf...methods
// <auto-generated />
partial class Employee
{
public required string Name
{
get => field;
set
{
ArgumentNullException.ThrowIfNull(value);
field = value;
}
}
public int Age
{
get => field;
set
{
ArgumentOutOfRangeException.ThrowIfLessThanOrEqual(value, 17);
field = value;
}
}
public decimal Salary
{
get => field;
set
{
ArgumentOutOfRangeException.ThrowIfNegative(value);
ArgumentOutOfRangeException.ThrowIfGreaterThan(value, 1234.56M);
field = value;
}
}
}
You focus on the model. The generator handles the guard clauses.
Works with CommunityToolkit.MVVM too
If you’re using the MVVM Toolkit’s [ObservableProperty] attributes, you can still use PropertyThrowGenerator. The toolkit already generates the property implementation, so this generator instead emits the appropriate On<Property>Changing partial methods containing the validation logic.
Example:
partial class Employee
{
[ThrowIfNull]
[ObservableProperty]
public required partial string Name { get; init; }
[ThrowIfGreaterThan("1234.56M")]
[ThrowIfNegative]
[ObservableProperty]
public partial decimal Salary { get; set; }
}
This produces:
-
OnNameChanging(string value) -
OnSalaryChanging(decimal value)
…each containing the correct ThrowIf calls .
// <auto-generated />
partial class Employee
{
partial void OnNameChanging(string value)
{
ArgumentNullException.ThrowIfNull(value);
}
partial void OnSalaryChanging(decimal value)
{
ArgumentOutOfRangeException.ThrowIfNegative(value);
ArgumentOutOfRangeException.ThrowIfGreaterThan(value, 1234.56M);
}
}
This makes the generator a perfect companion for MVVM projects.
Supported ThrowIf attributes
The package includes a full suite of validation attributes, including:
-
ThrowIfNull -
ThrowIfNullOrEmpty -
ThrowIfNullOrWhiteSpace -
ThrowIfEqual -
ThrowIfNotEqual -
ThrowIfGreaterThan -
ThrowIfGreaterThanOrEqual -
ThrowIfLessThan -
ThrowIfLessThanOrEqual -
ThrowIfNegative -
ThrowIfNegativeOrZero -
ThrowIfZero
Each maps directly to the corresponding Argument...Exception.ThrowIf... helper.
Analyzer rules
To help you catch mistakes early, the generator ships with two analyzers:
| Rule | Severity | Description |
|---|---|---|
| PTG001 | Error | C# language version is below 14.0 |
| PTG002 | Error | A ThrowIf attribute is used on a non‑partial property |
These ensure your project is correctly configured and your attributes are applied where they make sense.
Get started
The project is open‑source and available on GitHub:
👉 https://github.com/sonnemaf/ReflectionIT.PropertyThrowGenerator
It’s licensed under MIT, so feel free to explore, use, and contribute.
All postings/content on this blog are provided "AS IS" with no warranties, and confer no rights. All entries in this blog are my opinion and don't necessarily reflect the opinion of my employer or sponsors. The content on this site is licensed under a Creative Commons Attribution By license.
Blog comments
0 responses