1

Suppose we have this MCVE

class Person
{
    public int? Age;
    public string? Name;

    public bool IsInvalid => Name == null || Age == null;

    // ...

    public void Something(Person other) 
    {
        if (other.IsInvalid)
            return;

        Console.WriteLine(other.Name);
        Console.WriteLine(other.Age);
    }
}

This would complain to me because the compiler would rather have the expression for the property inside the if statement.

In my actual code, I have conditions like this but the property makes it more readable than checking for a series of nulls. Is there some attribute or something I can do to make the compiler realize that the property gives me non-null values?

I also fully understand that this might be a non-trivial task for a compiler to implement and as such it may not be possible right now.

This is also being done via .NET Core 3.0 Preview 9, so at the time of writing I have access to all the attributes that may exist.

Water
  • 3,245
  • 3
  • 28
  • 58
  • Would the `!.` (non-null assert, or "damn-it") operator solve the problem? (e.g. `other!.Name`) – madreflection Sep 10 '19 at 17:18
  • @madreflection It is both an option (and good idea), but then I'd have to use it in a fair amount of my code with that operator. I try to reserve that for only the most extreme cases because if someone refactors something then it's possible that operator could be a ticking time bomb. In the real world example I have: there is a fair amount of places where it'd have to be added and I'm too scared that I'm creating a recipe for disaster. My only other method of avoiding the issue would be to subclass and use `if (x is Y y)`, though it's in some performant-requiring area; unsure of `is` overhead. – Water Sep 10 '19 at 17:34
  • Those are fields, not properties. This matters. It means that attributes like [NotNullIfNotNull](https://learn.microsoft.com/en-us/dotnet/csharp/nullable-attributes#specify-conditional-post-conditions-notnullwhen-and-maybenullwhen) can't be applied to them. – Panagiotis Kanavos Sep 24 '19 at 11:56
  • If you dereference a nullable value twice, and mark the first with the damn-it operator, you will not get a warning for the second one, the compiler will trust you, so you shouldn't have to fix large swats of code. – Lasse V. Karlsen Sep 24 '19 at 12:39

1 Answers1

1

First of all, Age and Name are fields, not properties. This matters because it means attributes that apply only to properties can't be used, eg NotNullIfNotNull.

In any case, the attributes are used to specify pre- and post-conditions for specific code (methods, getters, setters etc), not object invariants. There's no attribute that can tie one property's nullability to another's value.

On the other hand, NotNullWhen can be used to tie a method's parameters to its return value, eg :

public bool GetValidValues([NotNullWhen(true)]out int? age, [NotNullWhen(true)]out string? name)
{
    age=Age;
    name=Name;
    return !IsInvalid;
}

Using GetValidValues doesn't generate any nullability warnings ;

public void Something(Person other) 
{
    if (!other.GetValidValues(out var age,out var name))
        return;

    Console.WriteLine(name.Length);
    Console.WriteLine(age);
}
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • I am marking this correct since "There's no attribute that can tie one property's nullability to another's value." is the answer I was looking for (at the time of writing this post). While the solution provided is even more characters to type than the larger solution. It is likely my fault that I didn't emphasize that I'm looking to minimize the number of characters to type and maximize readability, and the method provided is almost 2x larger than the solution I'm trying to avoid. Despite what I've said, I appreciate the idea you proposed. – Water Sep 24 '19 at 17:51
  • @Water you're asking for something that isn't available *yet*. This is the first version of the analyzer and has several limitations - [like the one in this question](https://stackoverflow.com/questions/57846038/c-sharp-8-switch-expression-not-smart-enough). The analyzer isn't context aware, which means it can't use the return type of an expression *yet* – Panagiotis Kanavos Sep 25 '19 at 07:49
  • Is there any plan for this to become a thing in X years? I don't know if by 'yet' you mean "the C# team are actively working towards things like this so you can expect it in anywhere from [duration here in months/years]" or "it has the potential to do that but no idea if it will happen and I'm just saying theoretically it could if the devs wanted to make it so" – Water Sep 25 '19 at 12:51
  • Looks like I lost my comment, I thought I posted it but apparently I didn't! So as a friendly reminder I'll ask again in case you happened to miss my previous comment since I am quite curious to what your response is. – Water Oct 06 '19 at 15:48