AL0015: Normalize null-guard style
Intent
Encourages consistent null-guard patterns across your codebase. When a method parameter or local variable needs a null check with ArgumentNullException, this analyzer suggests normalizing to a consistent form.
The analyzer recommends one of two patterns:
- BCL form (C# 6+ with
System.ArgumentNullException.ThrowIfNull): Cleaner, more idiomatic, and explicitly designed for this use case - Portable form (coalesce assignment with throw): Works across all .NET frameworks and is ideal for multi-target projects
The recommended form is determined automatically by:
- Project Target Framework Moniker (TFM) - single vs multi-target
- Language version support
- EditorConfig preference (
ancplua_nullguard_style)
When it triggers
AL0015 detects null-guard patterns that can be normalized. The following code patterns trigger the diagnostic:
// Pattern 1: is null check
if (x is null) throw new ArgumentNullException(nameof(x));
// Pattern 2: == null check
if (x == null) throw new ArgumentNullException(nameof(x));
// Pattern 3: is null with block statement
if (x is null)
{
throw new ArgumentNullException(nameof(x));
}
// Pattern 4: String literal parameter name (also normalized)
if (x is null) throw new ArgumentNullException("x");
All of these can be replaced with either the BCL form or portable form depending on your project's configuration.
Examples - Before and After
Example 1: BCL form (when ThrowIfNull is available)
For projects targeting .NET 6.0+ or C# 11+ that support ArgumentNullException.ThrowIfNull:
// Before
public void ProcessData(string? data)
{
if (data is null) throw new ArgumentNullException(nameof(data));
// ... rest of method
}
// After
public void ProcessData(string? data)
{
ArgumentNullException.ThrowIfNull(data);
// ... rest of method
}
Example 2: Portable form (for netstandard2.0 or multi-target projects)
For projects targeting older frameworks or multi-target scenarios:
// Before
public void ProcessData(string? data)
{
if (data is null) throw new ArgumentNullException(nameof(data));
// ... rest of method
}
// After (portable)
public void ProcessData(string? data)
{
data = data ?? throw new ArgumentNullException(nameof(data));
// ... rest of method
}
The coalesce assignment form is compatible with .NET Framework 4.7+, .NET Standard 2.0, and works everywhere that supports throw expressions (C# 7.0+).
Non-Examples (does NOT trigger)
The following patterns do not trigger AL0015 because they don't match the normalization targets:
// Multiple arguments - custom message or inner exception
if (x is null) throw new ArgumentNullException(nameof(x), "Custom message");
// Wrong parameter name - parameter name doesn't match variable
if (x is null) throw new ArgumentNullException(nameof(y));
if (x is null) throw new ArgumentNullException("wrong_name");
// Different exception type
if (x is null) throw new InvalidOperationException(nameof(x));
// Complex expressions (not simple variable checks)
if (obj.Value is null) throw new ArgumentNullException(nameof(obj));
if (M() is null) throw new ArgumentNullException(nameof(M));
// Not immediately thrown (assigned to variable, etc.)
var result = new ArgumentNullException(nameof(x));
if (x is null) throw result;
These patterns are left as-is because they have semantic differences or are already in their preferred form.
Configuration
EditorConfig Property
Use the ancplua_nullguard_style property in your .editorconfig file to control which form the analyzer recommends:
[*.cs]
ancplua_nullguard_style = auto
Allowed Values
| Value | Behavior |
|---|---|
auto (default) |
Automatic selection based on project configuration |
portable |
Always use coalesce assignment form (x = x ?? throw ...) |
bcl |
Only use ArgumentNullException.ThrowIfNull if available; otherwise no fix offered |
Automatic Selection (auto mode)
When using auto mode, the analyzer selects the form based on:
- Multi-target projects: Uses portable form for maximum compatibility
- Single-target with .NET 6.0+: Uses BCL form (
ThrowIfNull) - Other single-target frameworks: Uses portable form
.editorconfig Examples
Project targeting netstandard2.0:
[*.cs]
ancplua_nullguard_style = portable
Project targeting .NET 6.0+:
[*.cs]
ancplua_nullguard_style = auto
Enforce BCL style in modern projects:
[*.cs]
ancplua_nullguard_style = bcl