Nullable Types as Property - c#

Is it ok to construct my object entities with this type?
public class Patient
{
public Datetime? AdmissionDate { get; set; }
public double? AdmissionFee { get; set }
public int? RoomNumber { get; set }
}
WHat is the drawback if I implemented this in all my entities, because recently, I always encounter situation where I really need to set the value to null, specially in DateTime. My current solution was put DateTime.MinValue when fetching null datetimes record from the database, and when Im displaying the result to Ui, I just check it like this.
if (patient.AdmissionDate == Datetime.MinValue)
{
DisplayAdmissionDate(string.empty)
}
else
{
DisplayAdmissionDate(patient.AdmissionDate)
}
Yes, in gridview, I have to put it on the Databound event, so when i have million data to display, I thought checking each of the datetime's each loop was not the most elegant way so, to this problem, I find this ? type where I can put null values, and I'm planning to ?ed all my properties, so in the future, putting null values to this value types will not be a problem. Any advise guys? TIA

This is one of those situations where no single, dogmatic answer covers all cases.
You can’t get away with always using nullable types (or always avoiding them). You should think about each case and use the one that you actually need.
You mentioned that you often needed a nullable DateTime. So why can’t you just use a DateTime? in those cases? This should be an independent consideration from all other fields, especially ints.
The null value in nullable types is intended to mean the value is something like unspecified, unavailable or unknown. There are many situations where this concept exists (e.g. users on a website may or may not specify their date of birth, so that should be a DateTime?), but there are also many situations where this concept makes no sense (e.g. the number of items in a List — if the List itself isn’t null, then clearly it has a definite number of items, so that should be int, not int?).

The object always should contain at least one non-nullable ValueType as a Primary Key. In your case, you should use
public int ID {get;set;}
Doing this, you can always identify an object. The rest of the properties can be nullable.
The check for nullable is perfectly fine, unless the GridView can detect that on its own already. Nullable types were introduces exactly for that purpose, allowing a ValueType to have null as a value. The performance aspect should be minimal isn't complex in any way and optimizing it would be a case of premature optimization.
If you want to know more about the implementation of Nullable<T>, have a look here (sadly, the original page currently is down, so the webcache version has to be sufficient. The code is readable though, just the blogpost is abit broken).

The downside with nullable types is that you must always check to see wether they have a value or not before operating on them...
if(AdmissionFee.HasValue) total += AdmissionFee;
instead of just
total += AdmissionFee;

You may get problems with data binding, I don’t think WinForms will cope well as it predates nullable types.
If an item can be null in real life then a nullable type is a good solution as it makes the clear. However don’t just use them for the sake of it.

According to https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/property?redirectedfrom=MSDN:
AVOID throwing exceptions from property getters.
Since SomeNullableProperty.Value can throw a NullReferenceException, I'd say you should at least have logic in your getter to make sure there's a default value.

Related

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

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.
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:
tutorials: nullable reference types
Working with Nullable Reference Types
Nullable reference types

What is exclamation mark dot (!.) operator in C# [duplicate]

I've recently seen the following code:
public class Person
{
//line 1
public string FirstName { get; }
//line 2
public string LastName { get; } = null!;
//assign null is possible
public string? MiddleName { get; } = null;
public Person(string firstName, string lastName, string middleName)
{
FirstName = firstName;
LastName = lastName;
MiddleName = middleName;
}
public Person(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
MiddleName = null;
}
}
Basically, I try to dig into new c# 8 features. One of them is NullableReferenceTypes.
Actually, there're a lot of articles and information about it already. E.g. this article is quite good.
But I didn't find any information about this new statement null!
Can someone provide me an explanation for it?
Why do I need to use this?
And what is the difference between line1 and line2?
TL;DR
The key to understanding what null! means is understanding the ! operator. You may have used it before as the "not" operator. However, since C# 8.0 and its new "nullable-reference-types" feature, the operator got a second meaning. It can be used on a type to control Nullability, it is then called the "Null Forgiving Operator".
Basically, null! applies the ! operator to the value null. This overrides the nullability of the value null to non-nullable, telling the compiler that null is a "non-null" type.
Typical usage
Assuming this definition:
class Person
{
// Not every person has a middle name. We express "no middle name" as "null"
public string? MiddleName;
}
The usage would be:
void LogPerson(Person person)
{
Console.WriteLine(person.MiddleName.Length); // WARNING: may be null
Console.WriteLine(person.MiddleName!.Length); // No warning
}
This operator basically turns off the compiler null checks for this usage.
Technical Explanation
The groundwork that you will need to understand what null! means.
Null Safety
C# 8.0 tries to help you manage your null-values. Instead of allowing you to assign null to everything by default, they have flipped things around and now require you to explicitly mark everything you want to be able to hold a null value.
This is a super useful feature, it allows you to avoid NullReferenceExceptions by forcing you to make a decision and enforcing it.
How it works
There are 2 states a variable can be in - when talking about null-safety.
Nullable - Can be null.
Non-Nullable - Can not be null.
Since C# 8.0 all reference types are non-nullable by default.
Value types have been non-nullable since C# 2.0!
The "nullability" can be modified by 2 new (type-level) operators:
! = from Nullable to Non-Nullable
? = from Non-Nullable to Nullable
These operators are counterparts to one another.
The Compiler uses the information, you define with those operators, to ensure null-safety.
Examples
? Operator usage.
This operator tells the compiler that a variable can hold a null value. It is used when defining variables.
Nullable string? x;
x is a reference type - So by default non-nullable.
We apply the ? operator - which makes it nullable.
x = null Works fine.
Non-Nullable string y;
y is a reference type - So by default non-nullable.
y = null Generates a warning since you assign a null value to something that is not supposed to be null.
Nice to know: Using object? is basically just syntactic sugar for System.Nullable<object>
! Operator usage.
This operator tells the compiler that something that could be null, is safe to be accessed. You express the intent to "not care" about null safety in this instance. It is used when accessing variables.
string x;
string? y;
x = y
Illegal! Warning: "y" may be null
The left side of the assignment is non-nullable but the right side is nullable.
So it does not work, since it is semantically incorrect
x = y!
Legal!
y is a reference type with the ? type modifier applied so it is nullable if not proven otherwise.
We apply ! to y which overrides its nullability settings to make it non-nullable
The right and left side of the assignment are non-nullable. Which is semantically correct.
WARNING The ! operator only turns off the compiler-checks at a type-system level - At runtime, the value may still be null.
Use carefully!
You should try to avoid using the Null-Forgiving-Operator, usage may be the symptom of a design flaw in your system since it negates the effects of null-safety you get guaranteed by the compiler.
Reasoning
Using the ! operator will create very hard to find bugs. If you have a property that is marked non-nullable, you will assume you can use it safely. But at runtime, you suddenly run into a NullReferenceException and scratch your head. Since a value actually became null after bypassing the compiler-checks with !.
Why does this operator exist then?
There are valid use-cases (outlined in detail below) where usage is appropriate. However, in 99% of the cases, you are better off with an alternative solution. Please do not slap dozens of !'s in your code, just to silence the warnings.
In some (edge) cases, the compiler is not able to detect that a nullable value is actually non-nullable.
Easier legacy code-base migration.
In some cases, you just don't care if something becomes null.
When working with Unit-tests you may want to check the behavior of code when a null comes through.
Ok!? But what does null! mean?
It tells the compiler that null is not a nullable value. Sounds weird, doesn't it?
It is the same as y! from the example above. It only looks weird since you apply the operator to the null literal. But the concept is the same. In this case, the null literal is the same as any other expression/type/value/variable.
The null literal type is the only type that is nullable by default! But as we learned, the nullability of any type can be overridden with ! to non-nullable.
The type system does not care about the actual/runtime value of a variable. Only its compile-time type and in your example the variable you want to assign to LastName (null!) is non-nullable, which is valid as far as the type-system is concerned.
Consider this (invalid) piece of code.
object? null;
LastName = null!;
When the "nullable reference types" feature is turned on, the compiler tracks which values in your code it thinks may be null or not. There are times where the compiler could have insufficient knowledge.
For example, you may be using a delayed initialization pattern, where the constructor doesn't initialize all the fields with actual (non-null) values, but you always call an initialization method which guarantees the fields are non-null. In such case, you face a trade-off:
if you mark the field as nullable, the compiler is happy, but you have to un-necessarily check for null when you use the field,
if you leave the field as non-nullable, the compiler will complain that it is not initialized by the constructors (you can suppress that with null!), then the field can be used without null check.
Note that by using the ! suppression operator, you are taking on some risk. Imagine that you are not actually initializing all the fields as consistently as you thought. Then the use of null! to initialize a field covers up the fact that a null is slipping in. Some unsuspecting code can receive a null and therefore fail.
More generally, you may have some domain knowledge: "if I checked a certain method, then I know that some value isn't null":
if (CheckEverythingIsReady())
{
// you know that `field` is non-null, but the compiler doesn't. The suppression can help
UseNonNullValueFromField(this.field!);
}
Again, you must be confident of your code's invariant to do this ("I know better").
null! is used to assign null to non-nullable variables, which is a way of promising that the variable won't be null when it is actually used.
I'd use null! in a Visual Studio extension, where properties are initialized by MEF via reflection:
[Import] // Set by MEF
VSImports vs = null!;
[Import] // Set by MEF
IClassificationTypeRegistryService classificationRegistry = null!;
(I hate how variables magically get values in this system, but it is what it is.)
I also use it in unit tests to mark variables initialized by a setup method:
public class MyUnitTests
{
IDatabaseRepository _repo = null!;
[OneTimeSetUp]
public void PrepareTestDatabase()
{
...
_repo = ...
...
}
}
If you don't use null! in such cases, you'll have to use an exclamation mark every single time you read the variable, which would be a hassle without benefit.
Note: cases where null! is a good idea are fairly rare. I treat it as somewhat of a last resort.
I don't believe this question can be discussed without specific C# version being used.
public string RpyDescription { get; set; } = null!;
This is common in .NET 6 Core ... in fact it's required if you want to describe a string as not being nullable. One reason this exists is when one is working with SQL databases where a field can be set to "Allow Null". Even more so when working with JSON structures that accept null. EF needs to know.
Reference Type (Heap - pointer to memory location where the data is stored) of Value Type (Stack - memory location where data is stored).
.NET 6 (C#10) enables nullable context for the project templates by default (prior to this nullable context is disabled by default).
In EF/Core, it's very important to understand relationship between database null and model/entities null.
This question needs to be updated, in C# 10 in object relational mapping, this operator, combined with the ? operator is critical, this is a way to tell other coders on the project, future coders, and remind yourself how the data is going to end up being consumed and the null rules regarding that data.
public string Data { get; set; } = null!;
public string? Nullable { get; set; }
The beauty of this is that you don't have to go and look at the API docs(which you might not have), or go look through your database (which you might not even have access to). You already know by glancing at the class what the rules regarding null values are.
The downside is that if you instantiate the class, and don't have the information you need to instantiate the NOT NULL values, you will get strange default values that don't always make sense. First of all this doesn't happen nearly as commonly as people think and often comes from lazy programming. When you instantiate an instance of a class. You should calculating or assigning those NOT NULL properties. Right away. If you declare a car, and in your database or API cars have wheels, if you declare a car without assigning property values to the wheel.
Then did you truly instantiate the car in a meaningful way? You certainly didn't define the car the way the Database understands a car, it's a car with no wheels and it shouldn't be, doing this might be convenient but it goes against basic principles of object oriented programming.
are there exceptions for example perhaps the value can't be known at that point in time or until other events have transpired in these edge cases. Create a meaningful default value manually, if your default value hits the database you will know EXACTLY what's wrong
for people discussing unit tests why would you test the null case when the null case is impossible in the context of the object there is no need to have an understanding of how a car without wheels would behave for example. This is a silly, badly designed test.
I would go so far as to say that when it comes to strings this operator should be used the overwhelming majority of the time. When we declare int, or bool, or float, we have the understanding that these cannot be null unless we say so explicitly. Why in the world would you advocate for a different rule for strings!? the fact that we couldn't do this with strings previously was a design flaw.

Three valued logic with nullable bool?

I have a easy control with nothing chosen at begin and user decide to set yes or no. All in all a standard example for three valued logic.
So my first thought was to take nullable bool to persist. Normally this would leads me to some annoying if (var == null) { ... } (or something similar).
Second thought brings me to Enums.
public enum Selection
{
Yes,
No,
NotChoosenYet
}
In my context this brings to some enum to bool converts, but this is not a show-stopper.
All in all I tend to chose the "Enum-way", because is more readable.
I searched SO for a while but can't find a question which brings me a sept forward.
Is there a better way which I do not consider yet? Maybe a standard .Net-Type which can make thinks more easy?
I'd stick with ENUMS.
My three reasons that come to mind in a second:
It's more readable.
You avoid null poiters and unnecessary null-check code.
You can add another option (eg. 'Ask me later') without refactoring your whole source.
I would stick with the nullable boolean, as this is how you will represent it in the database.
Either NULL, Yes or No.
From Nullable Types (C# Programming Guide)
Nullable types are instances of the Nullable struct. A nullable type
can represent the correct range of values for its underlying value
type, plus an additional null value. For example, a Nullable,
pronounced "Nullable of Int32," can be assigned any value from
-2147483648 to 2147483647, or it can be assigned the null value. A Nullable can be assigned the values true false, or null. The
ability to assign null to numeric and Boolean types is especially
useful when you are dealing with databases and other data types that
contain elements that may not be assigned a value. For example, a
Boolean field in a database can store the values true or false, or it
may be undefined.
Also from Using Nullable Types (C# Programming Guide)
For an example of when you might use a nullable type, consider how an
ordinary Boolean variable can have two values: true and false. There
is no value that signifies "undefined". In many programming
applications, most notably database interactions, variables can occur
in an undefined state. For example, a field in a database may contain
the values true or false, but it may also contain no value at all.
Similarly, reference types can be set to null to indicate that they
are not initialized.
I would mimic the way it is stored in the database. If it is null, true and false in the db, then use null, yes, no in the c#-code. It is undecided, yes, no in the db then use the enum in the c#-code. Simply because this would be easier for the next guy.
If I choose between these two, the enum looks better.

How to represent data that may not be set

I have a class containing a number of properties, something like:
public class Update
{
public int Quantity { get; set; }
public decimal Price { get; set; }
public string Name { get; set; }
}
Each instance of Update does not necessarily have each property set, and another part of the system needs to know which have been set, and which haven't.
One option I've got is to make all the value types Nullable and so a null value would represent the concept of not being set. Whilst this would work, I don't really like the idea of having some properties explicitly Nullable (the value types) and some nullable by virtue of being a reference type. The class definition would look ugly and I'm not convinced a null check is semantically the best approach.
I could create a class very similar to Nullable<T> that has no constraint on the T with an IsSet property. I prefer this option to using Nullable, but I'd still like to see if anyone has an alternative representation that's better than the options I've suggested.
You really should stick to the preexisting idiom here. Use the built-in nullability.
I see your concern with nullability being different for value and ref types. Your workaround would work. But it is just a cosmetic change which gains you litte. I recommend that you change yourself instead of changing the code in this case. Try to fit yourself to the existing conventions.
Edit: Sometimes you need to be able to make a value optional in generic code. In this case you need to use some custom option type. By from experience I can tell that this is pretty nasty to use. It is not my solution of choice.
The reference types are already nullable, effectively - if you use int?, decimal? and string then every one of your properties can be null.
The problem comes if you ever want to set the string value to a null reference - if null is effectively a valid value which is set.
You certainly could write a Maybe<T> type, but I'm not sure I would - I would probably just use null... aside from anything else, it'll be more familiar for others reading the code who are used to C# idioms. For all the "anti-null" sentiment around (which I do share in many situations) there are cases where it's the simplest approach.
I don't really like the idea of having some properties Nullable (the
value types) and some not (the reference types)
Reference types are obviously nullable.
string t = null; //is totally valid
I'd say that Nullable is exactly what you want to use for this purpose.
You could wrap the members with properties (as you already do) to have the class show normal values to the outside alongside with "is it set"-methods to check if needed. But on the inside I'd use Nullable.
To suggest you something new... If you just talking about one class like Update with a limited number of members I would use just IsSet.
But if you have i.e. a number of similar classes with this behavior or a lot of properties I could suggest you using t4 templates. You can, in example, get class properties (of needed type or attribute) as it described in this article and auto generate code based on the list of properties (implementing any design you want automatically)
I could describe it more if one is interested...
The solution here to
use nullable wherever null is not a valid option
use a default value wherever null is a valid option but you are perfectly sure that a given value won't occur
use a boolean flag for each property where null is a valid value and you can't name a default which won't be used ever.
Examples:
Quantity should be nullable, because if it is set its value won't be null ever
Name should be defaulted to "" if Name might be null (the lack of a name) and you are sure Name will never be ""
A flag, let's say nameSet should be used if Name might have a null value and you can't think of a default value. This flag would be false by default and when you first set the value of Name, the flag should be set to true too.
If you want to handle all your properties in the same way a solution would be to create a class which would contain an Object and a boolean flag. The Object would store the value of the property and the flag would store whether the property was initialized, but I don't like this, because it creates a boolean flag even if it's not needed.

Why shouldn't I always use nullable types in C#

I've been searching for some good guidance on this since the concept was introduced in .net 2.0.
Why would I ever want to use non-nullable data types in c#? (A better question is why wouldn't I choose nullable types by default, and only use non-nullable types when that explicitly makes sense.)
Is there a 'significant' performance hit to choosing a nullable data type over its non-nullable peer?
I much prefer to check my values against null instead of Guid.empty, string.empty, DateTime.MinValue,<= 0, etc, and to work with nullable types in general. And the only reason I don't choose nullable types more often is the itchy feeling in the back of my head that makes me feel like it's more than backwards compatibility that forces that extra '?' character to explicitly allow a null value.
Is there anybody out there that always (most always) chooses nullable types rather than non-nullable types?
Thanks for your time,
The reason why you shouldn't always use nullable types is that sometimes you're able to guarantee that a value will be initialized. And you should try to design your code so that this is the case as often as possible. If there is no way a value can possibly be uninitialized, then there is no reason why null should be a legal value for it. As a very simple example, consider this:
List<int> list = new List<int>()
int c = list.Count;
This is always valid. There is no possible way in which c could be uninitialized. If it was turned into an int?, you would effectively be telling readers of the code "this value might be null. Make sure to check before you use it". But we know that this can never happen, so why not expose this guarantee in the code?
You are absolutely right in cases where a value is optional. If we have a function that may or may not return a string, then return null. Don't return string.Empty(). Don't return "magic values".
But not all values are optional. And making everything optional makes the rest of your code far more complicated (it adds another code path that has to be handled).
If you can specifically guarantee that this value will always be valid, then why throw away this information? That's what you do by making it a nullable type. Now the value may or may not exist, and anyone using the value will have to handle both cases. But you know that only one of these cases is possible in the first place. So do users of your code a favor, and reflect this fact in your code. Any users of your code can then rely on the value being valid, and they only have to handle a single case rather than two.
Because it's inconvenient to always have to check whether the nullable type is null.
Obviously there are situations where a value is genuinely optional, and in those cases it makes sense to use a nullable type rather than magic numbers etc, but where possible I would try to avoid them.
// nice and simple, this will always work
int a = myInt;
// compiler won't let you do this
int b = myNullableInt;
// compiler allows these, but causes runtime error if myNullableInt is null
int c = (int)myNullableInt;
int d = myNullableInt.Value;
// instead you need to do something like these, cumbersome and less readable
int e = myNullableInt ?? defaultValue;
int f = myNullableInt.HasValue ? myNullableInt : GetValueFromSomewhere();
I think the language designers feel that 'reference types being nullable by default' was a mistake, and that non-nullable is the only sensible default, and you should have to opt into nullness. (This is how it is in many modern functional languages.) "null" is usually a heap of trouble.
You seem to have 2 different questions...
Why would I ever want to use non-nullable data types in C#?
Simple, because the value-type data you're relying on is guaranteed by the compiler to actually have a value!
Why wouldn't I choose nullable types by default, and only use non-nullable types when that explicitly makes sense?
As Joel has already mentioned, a type can only be null if it is a reference type. Value types are guaranteed by the compiler to have a value. If your program depends on a variable to have a value, then this is the behavior you will want by not choosing a nullable type.
Of course, when your data is coming from anywhere that is not your program, then all bets are off. The best example is from a database. Database fields can be null, so you would want your program variable to mimic this value - not just create a "magic" value (i.e. -1, 0, or whatever) that "represents" null. You do this with nullable types.
Although null values can be convenient for using as "not-initialized-yet" or "not-specified" values, they make the code more complex, mainly because you're overloading the meaning of null as well as the variable (number-or-null vs. just-a-number).
NULL values are favoured by many database designers and SQL database programmers but with a small change in thinking about the problem you can do away with null values and actually have simpler and more reliable code (e.g., no worrying about NullReferenceExceptions).
There's actually a large demand for a "T!" operator that makes any reference type non-nullable, similar to how "T?" makes value types nullable, and Anders Hejlsberg, the inventor of C#, wished he had included the ability.
See also the question, Why is “null” present in C# and java?
I tend to use Nullable types wherever they make sense -- I won't care about performance until it's a problem, then I'll fix the few areas where it is and be done with it.
However, I also find that in general, most of my values end up being non-nullable. In fact, there are many times I'd actually like a NotNullable I can use with reference types to find out about a null problem when I get the null, not later on when I try to use it.
The only time that a Nullable Type should ever be used, is in the case that a certain field in a table of the database absolutely requires that a null be sent or received by the application at some point. Even in such a case, one should always try to find a way around using the Nullable Type. Bool isn't always your best friend.

Categories

Resources