Оператор нулевого безопасного разыменования останавливает вычисление всего выражения, как только оно достигает нуля. Поэтому, если deserializedBody
имеет значение null, он не будет пытаться оценить date
и не будет вызывать ToString()
ни для чего, поэтому вы не получите исключения.
Полный пример:
using System;
class Test
{
DateTime date = DateTime.UtcNow;
static void Main()
{
Test t = null;
// No exception thrown
Console.WriteLine(t?.date.ToString());
}
}
Здесь выражение t?.date.ToString()
эквивалентно:
t is null ? null : t.date.ToString()
(за исключением того, что t
оценивается только один раз). Это не эквивалентно
(t is null ? null : t.date).ToString()
... именно этого, я подозреваю, вы ожидали.
Но нет, это не защищает от ситуации, когда deserializedBody
не равно NULL, а deserializedBody.date
равно NULL.
Если вы ожидали предупреждения из-за C# 8 ссылочных типов, допускающих значение NULL, я считаю, что dynamic c выражения никогда не проверяются на null. В качестве примера рассмотрим:
class Test
{
public string? foo;
}
class Program
{
static void Main(string[] args)
{
Test t = new Test();
dynamic d = t;
Console.WriteLine(t.foo.Length); // Warning
Console.WriteLine(d.foo.Length); // No warning
Console.WriteLine(d.bar); // No warning for this either
}
}
I подозреваю Причина этого в том, что компилятор в основном не имеет информации о том, что такое d.foo
. В каждом случае, когда есть полезное предупреждение, будет еще один случай, когда предупреждение будет бесполезным. Когда вы находитесь на территории динамического набора c, вы уже приняли на себя определенную степень риска - было бы странно предупреждать, что разыменование d.foo
рискованно, когда доступ к d.foo
рискован для начала.