注意
本文涵蓋可為 Null 的參考型別。 您也可以宣告可為 Null 的實值型別。
你可以在程式碼中使用可空參考型別,且該程式碼在可 空知的情境中。 可為 Null 的參考型別、Null 靜態分析警告,以及 Null 容許運算子是選擇性的語言功能。 這些規則預設為關閉。 你可以在專案層級用建置設定控制 可空的上下文 ,或在程式碼中用 pragma 來控制。
C# 語言參考資料記錄了 C# 語言最新版本。 同時也包含即將推出語言版本公開預覽功能的初步文件。
文件中標示了語言最近三個版本或目前公開預覽版中首次引入的任何功能。
小提示
欲查詢某功能何時首次在 C# 中引入,請參閱 C# 語言版本歷史的條目。
重要
所有專案範本都會為專案啟用 可空上下文。 使用舊版範本建立的專案不包含這個元素,除非您在專案檔中啟用這些功能或使用 pragmas,否則這些功能會關閉。
在可為 Null 的感知內容中:
- 你必須初始化一個非空值的參考型態
T變數,且永遠無法指派可能是null的值。 - 你可以初始化一個參考型態
T?的變數,或用nullassignnull,但必須先與它進行null檢查,才能進行反參照。 - 當你對型態
T?為 的變數m應用 null 寬容運算子,如m!時,該變數被視為非 null。
編譯器透過上述規則強制區分非可空參考型別 T 與可空型參照型 T? 別。 類型為 T 的變數,以及類型為 T? 的變數是相同的 .NET 類型。 下列範例會宣告不可為 Null 的字串和可為 Null 的字串,然後使用 null 容許運算子將值指派給不可為 Null 的字串:
string notNull = "Hello";
string? nullable = default;
notNull = nullable!; // null forgiveness
變數和nullable兩者都notNull使用型String別。 因為不可空(non-nullable)和可空(nullable)型別都用同一個型別,所以你不能在多個位置同時使用可空的參考型別。 一般來說,你不能用可空的參考型別作為基底類別或實作介面。 你不能在任何物件建立或型別測試表達式中使用可空的參考型別。 你不能用可空的參考型別當作成員存取表達式的型別。 下列範例顯示下列建構:
public MyClass : System.Object? // not allowed
{
}
var nullEmpty = System.String?.Empty; // Not allowed
var maybeObject = new object?(); // Not allowed
try
{
if (thing is string? nullableString) // not allowed
Console.WriteLine(nullableString);
} catch (Exception? e) // Not Allowed
{
Console.WriteLine("error");
}
可為 Null 的參考和靜態分析
上一節中的範例說明可為 Null 參考型別的本質。 可為 Null 的參考型別不是新的類別型別,而是現有參考型別的註釋。 編譯器會使用這些註釋來協助您在程式碼中尋找潛在的 Null 參考錯誤。 不可為 Null 的參考型別與可為 Null 的參考型別之間沒有執行階段差異。 編譯器不會針對不可為 Null 的參考型別新增任何執行階段檢查。 優點是在編譯時期分析中。 編譯器會產生警告,協助您找出並修正程式碼中潛在的 Null 錯誤。 宣告意圖,編譯器會在程式碼違反該意圖時發出警告。
重要
可空參考註解不會帶來行為改變,但其他函式庫可能會利用反射來產生可空與不可空參考型別的不同執行時行為。 值得注意的是,Entity Framework Core 會讀取可為 Null 的屬性。 它會將可為 Null 的參考解譯為選擇值,並將不可為 Null 的參考解譯為必須值。
在可為 Null 的啟用內容中,編譯器會對任何參考型別 (可為 Null 和不可為 Null) 的變數執行靜態分析。 編譯器會將每個參考變數的 null-state 追蹤為 not-null 或 maybe-null。 不可為 Null 參考的預設狀態為 not-null。 可為 Null 參考的預設狀態為 maybe-null。
您應可放心對不可為 Null 的參考型別進行取值,因為其 null-state是 not-null。 若要強制執行該規則,如果不可為 Null 的參考型別未初始化為非 Null 值,編譯器就會發出警告。 你必須在宣告的地方指派本地變數。 必須在欄位初始設定式或每個建構函式中為每個欄位指派 not-null 值。 當將不可為 Null 的參考指派給狀態為 maybe-null 的參考時,編譯器會發出警告。 一般來說,不可空引用是 非空 的,當你取消引用這些變數時不會發出警告。
注意
如果您將 maybe-null 運算式指派給不可為 Null 的參考型別,編譯器會產生警告。 編譯器接著會產生該變數的警告,直到指派給 not-null 運算式為止。
你可以初始化或指派 null 到可空的參考類型。 因此,靜態分析必須判斷在取值之前變數是 not-null。 若判定一個可空參考為可能為 空,將其指派給不可空參考變數會產生編譯器警告。 下列類別顯示這些警告的範例:
public class ProductDescription
{
private string shortDescription;
private string? detailedDescription;
public ProductDescription() // Warning! shortDescription not initialized.
{
}
public ProductDescription(string productDescription) =>
this.shortDescription = productDescription;
public void SetDescriptions(string productDescription, string? details=null)
{
shortDescription = productDescription;
detailedDescription = details;
}
public string GetDescription()
{
if (detailedDescription.Length == 0) // Warning! dereference possible null
{
return shortDescription;
}
else
{
return $"{shortDescription}\n{detailedDescription}";
}
}
public string FullDescription()
{
if (detailedDescription == null)
{
return shortDescription;
}
else if (detailedDescription.Length > 0) // OK, detailedDescription can't be null.
{
return $"{shortDescription}\n{detailedDescription}";
}
return shortDescription;
}
}
下列程式碼片段顯示編譯器使用此類別時發出警告的位置:
string shortDescription = default; // Warning! non-nullable set to null;
var product = new ProductDescription(shortDescription); // Warning! static analysis knows shortDescription maybe null.
string description = "widget";
var item = new ProductDescription(description);
item.SetDescriptions(description, "These widgets will do everything.");
上述範例示範編譯器的靜態分析如何判斷參考變數的 null-state。 編譯器會針對 Null 檢查和指派套用語言規則,以通知其分析。 編譯器無法假設方法或屬性的語意。 如果您呼叫執行 Null 檢查的方法,編譯器不知道這些方法會影響變數的 null-state。 你可以在 API 中加入屬性,讓編譯器了解參數和回傳值的語意。 .NET 連結庫中的許多常見 API 都有這些屬性。 例如,編譯程式會將 IsNullOrEmpty 正確地解譯為空值檢查。 如需適用於 null-state 靜態分析之屬性的詳細資訊,請參閱可為 Null 屬性的文章。
設定可為 Null 的內容
你可以用兩種方式控制可空化的上下文。 在專案層級,加入 <Nullable>enable</Nullable> 專案設定。 在單一 C# 原始碼檔案中,加入 #nullable enable pragma 以啟用可空上下文。 請參閱設定可為 Null 策略的文章。 在 .NET 6 之前,新專案會使用預設值,<Nullable>disable</Nullable>。 從 .NET 6 開始,新專案會在專案檔中包含 <Nullable>enable</Nullable> 元素。
C# 語言規格
欲了解更多資訊,請參閱 C# 語言規範中的可空參考型別章節。