Table of Contents

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