Null validation in extracted method

Viewed 232

I use c# 8 and nullable analyzers in .csproj

<PropertyGroup>
  <Nullable>enable</Nullable>
  <RunAnalyzersDuringBuild>true</RunAnalyzersDuringBuild>
  <RunAnalyzersDuringLiveAnalysis>true</RunAnalyzersDuringLiveAnalysis>
</PropertyGroup>

Below code which validates request via extracted method, shows such warning:

enter image description here

class Program
{
    public void Foo(Data request)
    {
        Validate(request);

        request.Properties.TryGetValue("bar", out var bar);
    }

    private static void Validate(Data request)
    {
        if (request == null)
        {
            throw new ArgumentNullException(nameof(request));
        }

        if (request.Properties == null)
        {
            throw new ArgumentNullException(nameof(Data.Properties));
        }
    }
}

public class Data
{
    public Dictionary<string, string>? Properties { get; set; }
}

If I put validation code directly into method (like below) there is no warning.

Why is that?

How can I have Validation extracted and don't have warning?

class Program
{
    public void Foo(Data request)
    {
        if (request == null)
        {
            throw new ArgumentNullException(nameof(request));
        }

        if (request.Properties == null)
        {
            throw new ArgumentNullException(nameof(Data.Properties));
        }

        request.Properties.TryGetValue("bar", out var bar);
    }
}

public class Data
{
    public Dictionary<string, string>? Properties { get; set; }
}
1 Answers

I believe that currenty (if you want to keep validation of both request and request.Properties in the method Validation) the only way to fix this problem is to use null forgiving operator:

request.Properties!.TryGetValue("bar", out var bar);

If you consider extracting validation of the request.Properties from the method Validation then you can use attribute NotNullAttribute to fix the problem. Attribute NotNullAttribute specifies that an input argument was not null when the call returns. Using this attribute we can declare Validate the next way:

private static void Validate([System.Diagnostics.CodeAnalysis.NotNull] object? obj, string name)
{
    if (obj == null)
    {
        throw new ArgumentNullException(name);
    }
}

After calling this method Validate code analyzer know that the obj is not null, and it will not produce warnings for code that access obj.

Then we can use Validate without getting warnings:

public static void Foo(Data request)
{
    Validate(request, nameof(request));
    Validate(request.Properties, nameof(request.Properties));

    request.Properties.TryGetValue("bar", out var bar);
}
Related