Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply NotNullIfNotNull with multiple arguments #43906

Open
alrz opened this issue May 2, 2020 · 5 comments
Open

Apply NotNullIfNotNull with multiple arguments #43906

alrz opened this issue May 2, 2020 · 5 comments

Comments

@alrz
Copy link
Member

alrz commented May 2, 2020

Currently multiple NotNullIfNotNull behaves as if they are being OR'ed

using System;
using System.Diagnostics.CodeAnalysis;
#nullable enable
public class C {
    [return: NotNullIfNotNull("a")]
    [return: NotNullIfNotNull("b")]
    public object? M(object? a, object? b) {
        if (a != null && b != null)
          return new {a, b};
        return null;
    }
    
    void Test()
    {
        M(null, new()).ToString();   // no warnings (one expected)
        M(new(), null).ToString();   // no warnings (one expected)
        M(null, null).ToString();    // warns (ok)
        M(new(), new()).ToString();  // no warnings (ok)
    }
}

If this is the intended behavior, a possible solution is to permit multiple arguments on the attribute

[return: NotNullIfNotNull("a", "b")]
public object? M(object? a, object? b) 

So that we get a warning if either of arguments are possible nulls.

@jnm2
Copy link
Contributor

jnm2 commented May 2, 2020

Had a situation like this last week, but I didn't write it down. :-(

@wilhelmzapiain
Copy link

wilhelmzapiain commented Jun 9, 2020

I have a use case:

public static T Min<T>([AllowNull] T left, [AllowNull] T right)
    where T : IComparable<T>
    => left == null ? (right == null ? default : (right.CompareTo(left) > 0 ? left : right)) : (left.CompareTo(right) < 0 ? left : right);

If either left or right is null the return value may be null, depending on the implementation of IComparable<T> (although the spec for IComparable<T> says that if either one is null the return value is null.)

@jnm2
Copy link
Contributor

jnm2 commented Jun 9, 2020

@wilhelmzapiain That method would confuse me. I'd expect Enumerable.Min semantics: "the min of everything that isn't null"

@mikernet
Copy link

Alternate option: dotnet/csharplang#6981

@csharper2010
Copy link

@wilhelmzapiain That method would confuse me. I'd expect Enumerable.Min semantics: "the min of everything that isn't null"

Maybe but if you want to write a null-safe Plus operator in analogy to SQL semantics, you have a perfectly valid example for this issue.

Either a solution with...

[return: MayBeNullIfNull(nameof(left)), MayBeNullIfNull(nameof(right))] // with OR semantics
public static Value operator +(Value? left, Value right) {}

... or ...

[return: NotNullIfNotNull(nameof(left), nameof(right))] // with AND semantics
public static Value? operator +(Value? left, Value right) {}

... would be highly appreciated also for our project where we have such operators used in really many places and refactoring all of them out to fully apply nullable reference types would be hell.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Nullable Board
Awaiting triage
Development

No branches or pull requests

6 participants