10

Using C#8, Visual Studio 2019 16.7.2, given the following C# code:

#nullable enable

public async Task<string> GetStringAsync(); ...

public async void Main()
{
    var theString = await GetStringAsync();
    ...
}

Intellisense hovering over theString shows a tooltip of local variable (string?) theString

My GetStringAsync method never returns a nullable string, yet the variable is inferred as being nullable.

Is this an intellisense bug? Or is there something deeper going on where theString can actually be null due to some way that await works?

Tyler Mc
  • 228
  • 1
  • 7
Orion Edwards
  • 121,657
  • 64
  • 239
  • 328
  • 4
    Redirected to the compiler team through a [GitHub issue](https://github.com/dotnet/roslyn/issues/47114). We should get an answer soon whether this is a bug, not a bug, or by-design. – Youssef13 Aug 25 '20 at 12:01
  • This is not a behavior of vs 2019 version "Microsoft Visual Studio Community 2019 16.6.5". in this version intellisense shows "string". – Biju Kalanjoor Aug 25 '20 at 14:16
  • 1
    But, if you declare `theString` as `string theString` it will be `string` right? – Paulo Morgado Aug 25 '20 at 14:53
  • Does this answer your question? [Why does Visual Studio Type a Newly Minted Array as Nullable?](https://stackoverflow.com/questions/62267427/why-does-visual-studio-type-a-newly-minted-array-as-nullable) – Iliar Turdushev Aug 25 '20 at 16:19
  • Intellisense will also show you a message like: "'theString' is not null here.", so the information you need to use the variable correctly/safely should be readily available. – Rikki Gibson Aug 26 '20 at 14:49

1 Answers1

11

This is by-design and does not have to do with the await.

var is always nullable, from the spec:

var infers an annotated type for reference types. For instance, in var s = ""; the var is inferred as string?.

As such, you can't explicitly specify theString as non-nullable when you use var. If you want it to be non-nullable, use string explicitly.


As to why: In short, it's to allow scenarios like this:

#nullable enable

public async Task<string> GetStringAsync(); ...

public async void Main()
{
    var theString = await GetStringAsync();
    
    if (someCondition)
    {
        // If var inferred "string" instead of "string?" the following line would cause
        // warning CS8600: Converting null literal or possible null value to non-nullable type.
        theString = null;
    }
}

The compiler will use flow analysis to determine whether or not the variable is null at any given point. You can read more about the decision here.

Pathogen David
  • 619
  • 6
  • 9
  • 2
    Thanks! I had no idea that `var` was always nullable. Makes a lot of sense, and I guess I got sent down the wrong track thinking it was somehow related to async – Orion Edwards Aug 27 '20 at 00:39
  • I was thinking exactly the same thing, with we had some non null var... – Peter Dec 08 '21 at 11:17
  • 2
    Strange. You would think that if you want to assign null lateron, you'd have to write var theString = (string?) (await ....) instead. – efdee Mar 16 '22 at 18:40