Reputation: 3825
Consider the following code:
#nullable enable
class Foo
{
public string? Name { get; set; }
public bool HasName => Name != null;
public void NameToUpperCase()
{
if (HasName)
{
Name = Name.ToUpper();
}
}
}
On the Name=Name.ToUpper() I get a warning that Name is a possible null reference, which is clearly incorrect. I can cure this warning by inlining HasName so the condition is if (Name != null).
Is there any way I can instruct the compiler that a true response from HasName implies a non-nullability constraint on Name?
This is important because HasName might actually test a lot more things, and I might want to use it in several places, or it might be a public part of the API surface. There are many reasons to want to factor the null check into it's own method, but doing so seems to break the nullable reference checker.
Upvotes: 26
Views: 3053
Reputation: 10553
C# 9.0 introduced what you're looking for in the form of MemberNotNullWhenAttribute. In your case you want:
#nullable enable
class Foo
{
public string? Name { get; set; }
[MemberNotNullWhen(true, nameof(Name))]
public bool HasName => Name != null;
public void NameToUpperCase()
{
if (HasName)
{
Name = Name.ToUpper();
}
}
}
There's also MemberNotNullAttribute for unconditional assertions.
I looked around at the different attributes from System.Diagnostics.CodeAnalysis
and I couldn't find anything applicable, which is very disappointing. The closest you can get to what you want appears to be:
public bool TryGetName([NotNullWhen(true)] out string? name)
{
name = Name;
return name != null;
}
public void NameToUpperCase()
{
if (TryGetName(out var name))
{
Name = name.ToUpper();
}
}
It looks pretty cumbersome, I know. You can look at the MSDN docs for nullable attributes, maybe you'll find something neater.
Upvotes: 16
Reputation: 3825
In C# 9.0 check out [MemberNotNull(nameof(Property))]
and [MemberNotNullWhen(true, nameof(Property))]
attributes.
https://github.com/dotnet/runtime/issues/31877
Upvotes: 1
Reputation: 4074
String is a reference type, and nullable (e.g. int?
) is nullable value types. So you can't really do this string? myString
; What you need is this:
class Foo
{
public string Name { get; set; }
public bool HasName => !String.IsNullOrEmpty(Name); ////assume you want empty to be treated same way as null
public void NameToUpperCase()
{
if (HasName)
{
Name = Name.ToUpper();
}
}
}
Upvotes: -10