What's the goal of disable nullable and how do we use it when it disabled in the future?

Viewed 224

Since C# 10, Nullable will disabled by default.

I already saw so much article and video about Nullable, They just saying we won't worry Null reference exception any more.

Also they keep saing there is so much way to use it by: Disable, Enable, Warning, Annotations.....bla bla bla.

And They Introduce us a lot of ways to use it with : ?., ??, ??=, NotNullWhenTrue, NotNullWhenFalse...etc

But I didn't saw anyone tell us: How to use it when it disabled.

We have a lot of scenario to use null before.

1. Property:

// What is the default value when nullable disabled , and how way we should use it?
Public string Name { get; set; } 

2. Linq:

Person model = PersenList.Where(x => x.id == id).FirstOrDefault();
if (null != model)
{
   // Do something
}
// How should we do when nullable diabled, what is the default value now, and how way we could check it a default value or not?

3.Temporary variable:

string ageDescription = null;
if (student.Age > 13)
{
   ageDescription = "X";
}
if (student.Age > 15)
{
    ageDescription = "XL";
}
if (student.Age > 18)
{
    ageDescription = "XXL";
}

System.Diagnostics.Debug.WriteLine($"The Student size: {(ageDescription ?? "Not found")}");
// What should we do in this case, bring "Not found" at the began always?

Or

string description = null;

if (student.Score < 70)
{
    description = "C";
}
if (student.Score > 70)
{
    description = "B";
}
if (student.Score > 80)
{
    description = "A";
}
if (student.Score > 90)
{
    description = "AA";
}
student.description = description;

JsonConvert.Serialize(student, {with Ignore Null Option for save more space});
// How do we save the json size and space, if we disable the nullable?

Or

string value = null;
try {
        value = DoSomething();
        if (value == "Something1")
        {
            Go1();
        }
        if (value == "Something2")
        {
            Go2();
        }
        if (value == "Something3")
        {
            Go3();
        }

   } catch (Exception ex)
   {
        if (null == value)
        {
           GoNull();
        }
        else
        {
          GoOtherButException(ex)
       }
   }
// How should we handle this kind of problem?

4.Entity Framework

//The tables always has null field and how we deal with it when nullable disabled?

I know there are much more scenario we might handle. I feel like they just bluffing there are so many Nullable feature are Awesome, but not give us any direction or good way to point out.

I hope someone already use C#10, pointed us how to change our old fashioned code style after disabled Nullable, and give us some example to show us how we should do in the future. Thanks

--------Update1--------

I add some more variable examples.

--------Update2-------- Some foks just said that we could use whatevery way we want. that's based on you requirement. If you want to use it, just simply add ? like:

string? name = null

But I more hope they could just tell me: use String.Empty replace the null in every place. Ha ha....

But In that case every place I still need to check if ( variable != String.Empty), but we could avoid null reference exception, also I'm not sure String.Empty will take how much spaces in memory.

So why don't anyone tell us to do that: when they told us disable the nullable, we need to changing our code style with how way?

Another thing that is I really can't get that How do we check the default value of Linq when use FirstOrDefault(), before we always use if (null != model).

Maybe I really want to know: How is the world like in the future if we all disable the nullable.

1 Answers

First thing that I feel like needs clearing up is that nullable reference types being enabled will not impact if your code can build or not. It has no impact on default values.

Nullable reference types are meant to enable you to Express your design intent more clearly with nullable and non-nullable reference types. As is the title of the awesome tutorials: nullable reference types and I highly suggest anyone trying to dive into this feature to read it.

The nullable reference types feature allows you to explicitly state: I never expect this (nullable type) property to be unknown. Thus it should always have a value.

To state that you expect a property to always have a value you define it as usual

public string Text { get; set; }.

To explicitly state that a property is not certain to have a value it would be defined with a '?' after the type

public string? Text { get; set; }

Hopefully the intent of this feature is now, more or less, clear. Let's dig into your concrete questions.

1. Property:

your question:

// What is the default value when nullable disabled , and how way we should use it?
public string Name { get; set; } 

A string or class property without initialization will still be null. An int without explicit initialization will still be 0 and a boolean without explicit initialization will still default to false. As not to repeat the same text on how to use it I will only repeat this. You should use it to Express your design intent more clearly with nullable and non-nullable reference types. It is up to you to mark all classes in the solution with whether or not a property has this characteristic. No this is not fun to do. But you also don't need to do it in 1 go. You can easily just enable the feature (have a ton of warnings) and steadily progress towards a solution that has more or less all classes covered on this.

2. Linq:

Person model = PersonList.Where(x => x.id == id).FirstOrDefault();
// How should we do when nullable diabled, what is the default value now, and how way we could check it a default value or not?

If you have a Linq query where you are not certain you can actually find what you are looking for (as is the reality for a lot of cases) .FirstOrDefault() can still be used. But Person model should express that it might potentially be null by changing it to Person? model.

3.Temporary variable:

You want to have a temp variable that is null at first and assign it conditionally? No problem, just add that magic '?' after it.

OR! If you definitely know you are going to give it a value why not assign an empty value to it? For example:

string description = string.Empty;
if (student.Score < 70)
    description = "C";
// ... some more conditions ...
student.description = description;

4. Entity Framework

I reckon that in the data access layer it will become super clear which properties to mark as will never be null and the ones that might. Just take a look at the database model and queries / stored procedures and the null checks you do before writing to the database. Everything that is unable to be null in your database will be in your data model class and everything that might contain will be marked with the '?' after the type in the data model class.

What is the world like if Nullable Reference Types are enabled?

Your IDE will show you warnings of potential unexpected null. This will, if the team works to reduce warnings, result in properties that explicitly state if they could be null, or not. This is done by adding a "?" after the property type. If you are certain that something is not null you can add a "!" to suppress the warning.

For DTO classes the "!" is something that is used often. This is due to the necessity for the DTO class to have an empty constructor and its properties to be settable using set; or init; properties. A warning will be shown. Here either the warning can be disabled for the file or the properties can be initialized with a default value (which can be null) with the warning suppressed using the "!". For both ways the properties should be null guarded prior to using them.

Suppress the warning by setting a default value using "!":

public List<string> Comments { get; set; } = null!;

A usual occurring phenomenon of this is that you will most likely see null guard clauses decreasing. This can be done if you are certain that the code being called is guaranteed to comply with the nullable references types feature. It is worth noting that these properties might still be null and thus you open yourself up for null reference exceptions instead of argument null exceptions. Nonetheless in my opinion this is worth the clarity and reduced size. But to each their own on how they see this. Stackoverflow question: When to null-check arguments with nullable reference types enabled

The end result is that your code will clearly express which variables are expected, and thus should be worked with in a nullable manner, to be non existing sometimes. This might result in fewer guard clauses with the benefits of less (boilerplate) code if possible

References

I really do hope that I managed to help you out a bit. If you have any more thirst from knowledge beside the tutorial here are some more really good docs regarding nullable reference types:

Related