分享方式:


! (null-forgiving) 運算子 (C# 參考)

一元後綴 ! 運算子是 Null 容許或 Null 隱藏運算子。 在已啟用可為 Null 的註釋內容中,您可以使用 Null 容許運算子來為上述運算式隱藏所有可為 Null 的警告。 一元前綴 ! 運算子是邏輯否定運算子。 Null 容許運算子在執行階段沒有作用, 其只會藉由變更運算子的 Null 狀態來影響編譯器的靜態流量分析。 在執行階段,運算式 x! 會評估為基礎運算式 x 的結果。

如需可為 Null 參考型別功能的詳細資訊,請參閱可為 Null 的參考型別

範例

Null 容許運算子的其中一個使用案例,是用於測試引數驗證邏輯。 例如,請參考下列類別:

#nullable enable
public class Person
{
    public Person(string name) => Name = name ?? throw new ArgumentNullException(nameof(name));

    public string Name { get; }
}

您可以使用 MSTest 測試架構來為建構函式中的驗證邏輯建立以下測試:

[TestMethod, ExpectedException(typeof(ArgumentNullException))]
public void NullNameShouldThrowTest()
{
    var person = new Person(null!);
}

因為缺少 Null 容許運算子,所以編譯器會為上述指令碼產生以下警告:Warning CS8625: Cannot convert null literal to non-nullable reference type。 您可以使用 Null 容許運算子,來向編譯器指示傳遞 null 是預期行為且不應產生警告。

當您確信運算式不可能是 null 但編譯器無法認知這點時,您也可以使用 Null 容許運算子。 在以下範例中,如果 IsValid 方法傳回 true,則其引數不會為 null,所以您可以放心對其取值 (Dereference):

public static void Main()
{
    Person? p = Find("John");
    if (IsValid(p))
    {
        Console.WriteLine($"Found {p!.Name}");
    }
}

public static bool IsValid(Person? person)
    => person is not null && person.Name is not null;

因為缺少 Null 容許運算子,所以編譯器會為p.Name 指令碼產生以下警告:Warning CS8602: Dereference of a possibly null reference

如果您可以修改 IsValid 方法,則您可以使用 NotNullWhen 屬性來指示編譯器當方法傳回 true 時,IsValid 方法的引數不可能為 null

public static void Main()
{
    Person? p = Find("John");
    if (IsValid(p))
    {
        Console.WriteLine($"Found {p.Name}");
    }
}

public static bool IsValid([NotNullWhen(true)] Person? person)
    => person is not null && person.Name is not null;

您不需要在上述範例中使用 Null 容許運算子,因為編譯器有足夠的資訊了解 pif 陳述式中不可能為 null。 如需詳細資訊以了解能針對變數 Null 狀態提供其他資訊的屬性,請參閱使用屬性升級 API 以定義 Null 預期

C# 語言規格

如需詳細資訊,請參閱可為 Null 參考型別規格的草稿Null 容許運算子一節。

另請參閱