As part of moving towards C# 8 nullable reference types, I encountered the following code (simplified):
public string GetIfExists(string key)
{
dict.TryGetValue(key, out var value);
return value;
}
The return
line warns on a possible null reference return, and it makes sense. So I tried to annotate the method with a [return: MaybeNull]
attribute, but the warning remained to my surprise. From the documentation, I understand that this attribute marks the return type as optional null
, even when the actual type doesn't allow it.
It seems that my only option to avoid warnings is to mark the return type string?
. So what is the use of [return: MaybeNull]
?
NotNull: A nullable field, parameter, property, or return value will never be null. MaybeNullWhen: A non-nullable argument may be null when the method returns the specified bool value. NotNullWhen: A nullable argument won't be null when the method returns the specified bool value.
The nullable annotation context determines the compiler's behavior. There are four values for the nullable annotation context: disable: The compiler behaves similarly to C# 7.3 and earlier: Nullable warnings are disabled. All reference type variables are nullable reference types.
In C# 8.0, strings are known as a nullable “string!”, and so the AllowNull annotation allows setting it to null, even though the string that we return isn't null (for example, we do a comparison check and set it to a default value if null.)
From the documentation:
[return: MaybeNull]
informs callers that the contract implies a non-nullable type, but the return value may actually be null. Use the MaybeNull attribute when your API should be a non-nullable type, typically a generic type parameter, but there may be instances where null would be returned.
This means that you want to use the attribute when you want the warning to be shown without changing the contract.
It seems that the attribute has been created to help enforce non-nullability (propagating a warning that forces the user to check for null) in two scenarios:
T?
, but you would still like the users of the method to be aware that the result needs to be checked. The only way you have to get rid of the warning is to change the return type to string?
(or return value!;
, but it would be a lie :p).
Your issue is irreproducible.
public string GetIfExists ( string key )
{
new Dictionary<string, string>().TryGetValue (key, out string value); // Warning CS8600 Converting null literal or possible null value to non-nullable type.
return value; // Warning CS8603 Possible null reference return.
}
[return: MaybeNull]
public string GetIfExists ( string key )
{
new Dictionary<string, string>().TryGetValue (key, out string? value);
return value;
}
(No issue‼)
From usage perspective for generics there is no difference between T?
return type
and [return: MaybeNull]
. (Applies also to reference type
.)
[return: MaybeNull]
public T Find<T> ( ) => default;
public T? Find2<T> () => default;
public T Find3<T> ( ) => default; // Warning CS8603 Possible null reference return.
void Test ()
{
object x = Find<object> (); // Warning CS8600 Converting null literal or possible null value to non-nullable type.
object x2 = Find2<object> (); // Warning CS8600 Converting null literal or possible null value to non-nullable type.
object x3 = Find3<object> ();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With