I was looking over some code and suggested a fix for verifying something isn't null that can be null and suggested the following:
// Path: Employee.cs
public class Employee(string name, DateTime? arrivalTime = null) {
public string Name = name;
public DateTime? ArrivalTime = arrivalTime;
}
// Path: Program.cs
class Program
{
static void Main(string[] args)
{
var testDate = DateTime.ParseExact(
"2024-12-10 10:30:00",
"yyyy-MM-dd HH:mm:ss",
System.Globalization.CultureInfo.InvariantCulture
);
var employees = new List<Employee>([
new Employee("Matt"),
new Employee("John", testDate),
new Employee("Steve")
]);
foreach (var employee in employees)
{
if (employee.ArrivalTime == null) continue;
var arrivalDate = DateOnly.FromDateTime(employee.ArrivalTime!);
Console.WriteLine($"{employee.Name} arrives at {arrivalDate}.");
}
}
}
I assumed the null-forgiving operator would work. From my understanding, and reading the reference documentation it should suppresses the null value error. But I get the following error when compiling: "error CS1503: Argument 1: cannot convert from 'System.DateTime?' to 'System.DateTime'".
I'm using the .NET 8.0.404 SDK.
However, changing the code to
var arrivalDate = DateOnly.FromDateTime((DateTime)employee.ArrivalTime);
or
var arrivalDate = DateOnly.FromDateTime(employee.ArrivalTime ?? DateTime.Now);
makes it work fine.
Basically, my question is why does it not understand that a null suppression is safe in this context? My LSP understands that it's a nullable value if I remove the null check and warns me about it, but even with the null check it doesn't allow me to use the !
operator. Am I misunderstanding the operator usage?
Thanks in advance. :)
!
(null-forgiving) not working as expected
It actually is
it should suppresses the null value error
No, it suppresses the warnings coming from the null-state analysis performed by compiler. For example the following:
foreach (var employee in employees)
{
var arrivalDate = DateOnly.FromDateTime(employee.ArrivalTime.Value);
Console.WriteLine($"{employee.Name} arrives at {arrivalDate}.");
}
Will produce the warning:
Warning CS8629 : Nullable value type may be null.
Which can be suppressed with the !
operator:
// will throw at runtime if ArrivalTime is null
var arrivalDate = DateOnly.FromDateTime(employee.ArrivalTime!.Value);
This operator is used when you know that the value will never be null here but compiler can't prove it and is a way to tell the compiler "shut up, I'm smarter" (which is obviously not always the case and I personally have shot myself in the foot several times with !
)
DateTime?
is a nullable value type which is actually Nullable<DateTime>
which does not have an implicit cast to DateTime
, so you need to get DateTime
which is usually done via the Value
property of the Nullable<T>
struct as was done in the preceding code.
Read more: