I have a simple class like this.
public class Greeting
{
public string From { get; set; }
public string To { get; set; }
public string Message { get; set; }
}
Strangely I get the following warning.
Severity Code Description Project File Line Suppression State
Warning CS8618 Non-nullable property 'From' must contain a non-null value when exiting constructor.
Consider declaring the property as nullable. MxWork.Elsa2Wf.Tuts.BasicActivities
D:\work\MxWork\Elsa2.0WfLearning\MxWork.Elsa2.0Wf.Tuts\src
\MxWork.Elsa2Wf.Tuts.BasicActivities\Messages\Greeting.cs 5 Active
I am baffled. These new kind of messages that it throws pulls down my confidence. I got them from all the three properties. And this has suddenly appeared.
Can some one please suggest how this can be mitigated.
These days I have seen using default! like so, and its working.
public class Greeting
{
public string From { get; set; } = default!;
public string To { get; set; } = default!;
public string Message { get; set; } = default!;
}
Also you may put a question mark symbol(?) to indicate that the type is nullable, if you feel appropriate as follows.
public class Greeting
{
public string? From { get; set; };
public string? To { get; set; };
public string? Message { get; set; };
}
The compiler is warning you that the default assignment of your string property (which is null) doesn't match its stated type (which is non-null string).
This is emitted when nullable reference types are switched on, which changes all reference types to be non-null, unless stated otherwise with a ?.
For example, your code could be changed to
public class Greeting
{
public string? From { get; set; }
public string? To { get; set; }
public string? Message { get; set; }
}
to declare the properties as nullable strings, or you could give the properties defaults in-line or in the constructor:
public class Greeting
{
public string From { get; set; } = string.Empty;
public string To { get; set; } = string.Empty;
public string Message { get; set; } = string.Empty;
}
if you wish to retain the properties' types as non-null.
Having nullable reference types turned on will save you a lot of heartaches when it comes to running your application. The problem with a lot of warnings is that most may not cause a problem, but it may hide that one that is causing a hard-to-find bug.
There are a few gotchas in using it like the question points out and answer very well by Slate and others.
It is a very good idea to have as near as possible to zero warning.
With nullable enabled, it produces a lot of warnings. Many times the compiler just knows something could be null. However, you being smarter than the compiler you know that by the time it reaches that code it won't be null.
For example:
public partial class Exams: ComponentBase
{
[Inject] private IQuestionPoolFetchService? QPoolService { get; init; }
private async Task FetchQuestionPool()
{
await QPoolService.GetAllQuestionsFromText();
}
This will throw a CS8602 warning. Because maybe somehow the DI will send a null. Of course, we know that isn't going to happen.
You could get rid of the warning with #prama like:
public partial class Exams: ComponentBase
{
[Inject] private IQuestionPoolFetchService? QPoolService { get; init; }
private async Task FetchQuestionPool()
{
#pragma warning disables CS8602 // Dereference of a possibly null reference.
await QPoolService.GetAllQuestionsFromText();
#pragma warning restore CS8602 // Dereference of a possibly null reference.
}
This is very ugly code and gets worst if you have to repeat it many times.
A better solution: Using the null-forgiving operator. "!"
public partial class Exams: ComponentBase
{
[Inject] private IQuestionPoolFetchService? QPoolService { get; init; }
private async Task FetchQuestionPool()
{
await QPoolService!.GetAllQuestionsFromText();
// null-forgiving ^
}
This tells the compiler hey, I know this could be null, but it won't be.
You can annotate a property directly as non-nullable.
public string Property{ get; set; } = null!;
And it will give a warning if user tries to set the Property as null
You can also implement a constructor to remove the error.
public class Greeting
{
public string From { get; set; }
public string To { get; set; }
public string Message { get; set; }
public Greeting(string from, string to, string message)
{
From = from;
To = to;
Message = message;
}
}
For Entity Framework Working with nullable reference types:
public class NullableReferenceTypesContext : DbContext {
public DbSet<Customer> Customers => Set<Customer>();
public DbSet<Order> Orders => Set<Order>();
}