Why does Visual Studio Type a Newly Minted Array as Nullable?
Visual Studio with C# 8 allows you to use nullable types according to the contexts you setup in your project. You can find docs Here.
One way to enable it is with a <Nullable>enable</Nullable>
entry in your project file. If you have that then it'll choose to use the nullable type when you convert to explicit variable.
I'm not sure if that same behavior would be used for the other ways - pragmas for example - to enable it. I only tried the project file method.
Non-nullable reference type: why is my object considered nullable by the compiler?
In the original implementation, foo
would have been inferred as a Foo
.
However, people complained that this got in the way of things like:
string? GetThing() => ...
var result = "";
if (condition)
{
result = GetThing();
}
If result
is inferred as a string
, then the result = GetThing()
line causes a warning: GetThing()
returns a string?
, and there's a warning if you try and assign a string?
to a string
.
The solution was to infer result
as a string?
, but the compiler knows that it's currently not null (its "flow state" is "NotNull").
This means that:
string? GetThing() => ...
var result = "";
// No warning, as the compiler knows that result isn't null
int l1 = result.Length;
if (condition)
{
result = GetThing();
}
// Warning: the compiler knows 'result' might have been re-assigned
int l2 = result.Length;
For other examples of the flow state at work, see things like:
string? result = GetString();
if (result == null)
throw new Exception();
// No warning: the compiler knows that result can't be null here: if it was,
// the exception above would have been thrown
int l1 = result.Length;
string? result = GetString();
// Warning: result might be null
int l1 = result.Length;
// No warning: the compiler knows that result can't be null here: if it was,
// the line above would have thrown
int l2 = result.Length;
string result = "hello";
if (result == null)
Console.WriteLine("NULL!");
// Warning: because we checked for null above, the compiler assumes that we
// know something that it doesn't, and so result might be null.
int l1 = result.Length;
In C# 8, why does type inference on new expressions result in nullable references?
If var
were to infer its nullability from the expression, then in many instances you would not be able to assign a null
to it later on. For example, var s = "";
.
There was a discussion to allow var?
to express "the nullable version of the type", but it had several issues. Would the regular var
be restricted to infer a non-nullable type?
If yes, then (1) we're creating adoption pain as users need to add more ?
annotations, (2) we have an inconsistent nullability with var
pattern which had already shipped, (3) there are some questions with nullable value types (int?
).
If no, then the intent of the code would not be very clear. var?
would clearly indicate a nullable type, but var
would be a mixed bag of nullable and non-nullable.
The decision to infer a nullable type for var
was recorded in the LDM notes from 2019-12-18.
Why does async/await in C# return nullable values even when told not to?
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, invar s = "";
thevar
is inferred asstring?
.
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.
Can this value really ever be null, or is the C# compiler just confused by code?
Probably the code analyzer is not sufficiently intelligent to conclude your date
and time
can never be null.
You can inform it of that fact by using the 'null forgiving' operator:
public static DateTime JoinNullableDateTime(DateTime? date, DateTime? time)
{
...
else
return date!.Value.Date.Add(time!.Value.TimeOfDay);
}
Why isn't a type constraint of where T : object compiling in C# 8
This is a valid question and the answer is not trivial. Things have changed a lot since the initial proposal, for valid reasons. Using the object?
syntax would lead to confusion in other places.
The link points to the proposal document, not the actual documentation or specification. You'll find the documentation in the C# Guide's Nullable Reference Types. There's no referecence to generic constraints there. The Constraints on type parameters article doesn't mention object?
either, but it does mention the notnull
constaint.
The changes and the reasons behind them are explained in Try out Nullable Reference Types.
The common case: Nulls allowed
This :
public class A<T>
{
T DoStuff(T input)
{
return input;
}
}
Accepts any struct or value type, including null types. The following line doesn't generate any warnings :
var x=new A<string?>();
notnull constraint
You have to specify that you want non-nullable types with the notnull
constraint :
public class A<T>
where T:notnull
{
T DoStuff(T input)
{
return input;
}
}
Using string?
as a type parameter creates a warning now:
warning CS8714: The type 'string?' cannot be used as type parameter 'T' in the generic type or method 'A'. Nullability of type argument 'string?' doesn't match 'notnull' constraint.
The problem with T?
To use nullable types you have to specify whether the type is a class or struct. The reason for this is explained in The issue with T?
section of the blog post that introduced NRTs. T?
implies that T
is non-nullable so what is T
? Class or Struct? The compiler handles each case differently. With a struct, the compiler will generate a Nullable<T>
type while classes are handled by compiler magic.
This code :
public class A<T>
{
T? DoStuff(T input)
{
return input;
}
}
Will throw a compiler error, not just a warning :
A nullable type parameter must be known to be a value type or non-nullable reference type. Consider adding a 'class', 'struct', or type constraint.
Adding the class
constraint and passing string
as the type parameter doesn't generate any errors or warnings :
public class A<T>
where T:class
{
T? DoStuff(T input)
{
return input;
}
}
var x=new A<string>();
Related Topics
Determining If File Exists Using C# and Resolving Unc Path
Extremely Large Single-Line File Parse
What Exactly Is an Assembly in C# or .Net
How to Print Out a Tree Structure
C# - Volatile Keyword Usage VS Lock
Is It Secure to Store Passwords in Cookies
Convert Int to a Bit Array in .Net
Open Source Cad Drawing (Dwg) Library in C#
Processinfo and Redirectstandardoutput
C# 3.0 Generic Type Inference - Passing a Delegate as a Function Parameter
Delete Specific Line from a Text File
Selenium Stops When Browser Is Manually Interrupted
.Net - Convert Generic Collection to Datatable
In C#, How to Instantiate a Passed Generic Type Inside a Method
Hosting Clr in Delphi With/Without Jcl - Example
How to Run Multiple SQL Commands in a Single SQL Connection