Оператор, прощающий нуль (!), не работает в C# >= 8.0

#c# #c#-8.0

Вопрос:

Я попытался использовать этот прощающий нуль оператор (!) в Unity 2020.3.1f1 с vscode. Ни один из этих инструментов не видел, как работает этот синтаксис, поэтому я воспроизвел его в этих двух скрипках, вдохновленных документами:
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-forgiving

Один и тот же код для обоих:

 using System;

public class Program
{
    #nullable enable
    public struct Person {
        public string name;
    }
    
    static Person? GetPerson(bool yes) {
        Person ret = new Person();
        ret.name = "coucou";
        if(yes) return ret;
        else return null;
    }
    
    public static void Main()
    {
        Person? person = GetPerson(true);
        if(person != null) Console.WriteLine("name: "   person!.name);
    }
}
 

Сначала с C# 7.3 не работает должным образом, как ожидалось: https://dotnetfiddle.net/HMS35M

Во-вторых, с C# 8.0, по крайней мере, просто игнорируя синтаксис, кажется: https://dotnetfiddle.net/Mhbqhk

Есть идеи, как сделать так, чтобы это второе сработало?

Комментарии:

1. Это работает. Опубликуйте свой код в самом вопросе

2. @PanagiotisKanavos готово

3. @HansKilian Первое очевидно из сообщения, второе-8 или 9 после этого: docs.microsoft.com/en-us/dotnet/csharp/language-reference/…

Ответ №1:

Оператор, прощающий нуль , не применяется к Nullable<T> — остаются только доступные соответствующие элементы .Value , .HasValue и .GetValueOrDefault() ; вам придется использовать немного более длинное person.Value.name / person.GetValueOrDefault().name , или вы могли бы зафиксировать значение во время if теста:

 if (person is Person val) Console.WriteLine("name: "   val.name);
 

Комментарии:

1. спасибо за изучение этого нового синтаксиса, одна строка сохранена для приведения!

Ответ №2:

Оператор, прощающий нуль(Черт возьми), позволяет вам уведомлять компилятор о том, что он должен игнорировать возможную нулевую ссылку, потому что у вас больше информации, чем у компилятора.

Сначала с C# 7.3 не работает должным образом, как ожидалось: https://dotnetfiddle.net/HMS35M

Это null-forgiving operator не было реализовано до C# 8.0, вам понадобится пакет nuget или какой-либо альтернативный обходной путь, чтобы использовать символ взрыва в этом контексте для C#7.3.

Есть идеи, как сделать так, чтобы это второе сработало?

При использовании a Nullable<T> struct вы можете использовать .Value свойство для получения значения объекта(фактического Person struct , определенного вами). Без .Value метода компилятор не знает, пытаетесь ли вы получить доступ к Nullable<T> объекту или struct к определенному вами объекту. Поэтому он не может найти .name поле на Nullable<T> объекте.

Это должно сработать для вас

 if (person != null) Console.WriteLine("name: "   person!.Value.name);