If we take a look to the code below:
using System;
using System.Runtime.CompilerServices;
namespace S3236;
public class MyModel
{
public MyModel(int? total = null)
{
NotNegative(total ?? 0, nameof(total)); // Inconvenient report
Total = total;
}
public int? Total { get; init; }
private static int NotNegative(int parameter, [CallerArgumentExpression(nameof(parameter))] string? paramName = null)
=> parameter < 0
? throw new ArgumentOutOfRangeException(paramName, "Value should not be negative.")
: parameter;
}
The NotNegative check is only implemented for int and not for int?. To be able to test the constraint, the ?? 0 is passed, so that default<int> also succeeds. However, S3236 reports on caller information being dropped. Although true, you could argue that given the constraints this is the cleanest solution:
- Having an overload
NotNegative(int? parameter)could potentially returnintand guard tonulltoo (that would at least be consistent with other methods in the actualGuardclass). if(total is not null) NotNegative(total);(with or without nesting and/or brackets is not easier to read.- Having a parameter name
"total ?? 0"is not the right parameter to call on. - Using any form of suppression makes things worse (from a readability perspective)
So, I think I would like to see an exception made when a nameof() is used, and in the expression that nameof() is used. I see the risk of introducing false negatives, but I would guess that likeliness is low.
Note, to simplify the reproduction, this case has been simplified. The guarding method lives somewhere else in my case.
Reported by SonarAnalyzer.CSharp v10.29.0.143774