Categories
程式開發

C#的未來:簡化參數空值驗證


乍一看,提案#2145似乎是C# 8可空引用類型特性的邏輯擴展。其基本思想是,開發人員不需要再顯式地向接受非空參數的方法添加參數空值檢查。然而,人們對於這個特性的爭議很大。

本文試圖說明這些選項以及它們的利弊,以便讀者能夠得出自己的看法。但在此之前,本文將簡要說明為什麼這在C# 8中仍然很重要。

目前,可空引用類型特性只是提供信息。它會警告開發人員在處理空值時的常見錯誤,但僅在編譯時發出警告。當應用程序運行時,所有這些編譯時檢查都不存在。

此外,在使用反射或dynamic時,編譯檢查根本不起作用。

特定語法:感嘆號操作符

原來的建議是使用感嘆號操作符!告訴編譯器應添加參數空值檢查。

//输入的代码
void Insert(string value!) 
{
    ...
}
//编译后的代码
void Insert(string value) 
{
    if (value == null)
        throw new ArgumentNullException(nameof(value));
    ...
}

這個選項的理由是它破壞性小。它只需要對C#編譯器做一個小的修改,並且新語法完全向後兼容。
反對這一選項的理由是:

  • 它是一種適用面很窄的新語法;
  • 在閱讀代碼時很容易忽略它;
  • 很容易忘;
  • 聲明參數不可為空是多餘的。

另一個問題是,value!可能意味著“請檢查這個值是否為空”或“不需要檢查,我知道它不是空的”,這取決於上下文。為了解決後一個問題,這個提案的一個變體是使用雙感嘆號操作符(string value!!)。

新屬性

另一個選項是增加編譯器可以識別的新屬性,而不是新語法。

void Insert((NotNull) string value)

就C#而言,影響編譯代碼的屬性並不是什麼新東西,所以這可以與現有的模式保持一致。如果我們以前有聲明性參數驗證,它也會是這樣的。
反對這一選項的理由是:

  • 與正在考慮的其他選項相比,它非常囉嗦;
  • 聲明參數不可為空是多餘的。

編譯標識

下一個要考慮的選項是全局編譯器標識。當該標識啟用時,將檢查所有非空參數。

這個選項的好處是你不需要考慮它。一旦啟用,檢查就會自動添加,這樣就不會忘記,也不需要學習特殊的語法。

對此,第一個反對意見是,這可能存在性能方面的考慮。該選項的支持者認為,性能成本微不足道,該特性可以選擇性地僅應用於公共方法,但可以對任何方法調用執行空值檢查。

反對此特性的另一個理由是,開發人員可能希望拋出不同的異常。與此相反的觀點是,除了ArgumentNullException之外,他們不應該拋出任何東西。此外,編譯器指令可以在需要特殊處理時僅針對一個文件或方法禁用該特性。

最後一個觀點最有說服力。這將是編譯器標識第二次改變代碼的語義。諸如“nullable”之類的編譯器標識實際上並不會改變代碼的行為方式,它只是一個編譯時特性。

這個規則有個例外,就是’checked’編譯器標識,它會改變整數溢出的行為。在C#語言設計人員中,這被認為是一個錯誤,因為如果不知道編譯器級如何設置標識,你就無法判斷給定代碼段的操作方式。

反對的觀點並沒有反駁這一點,但是,保持這項更改是使可空引用類型特性接近完成的必要步驟。對此,一些人堅持認為,NRT從來就不是一個完備的解決方案,為了向後兼容,它不應該影響運行時行為。

外部AOP和IL織入

術語“IL織入(IL weaving)”指的是在編譯器完成後修改程序集的後處理步驟。這用於面向方面的編程工具,如PostSharp和已取消的Code Contracts項目。

爭論中提到了具體的工具Fody NullGuardFody是遵循MIT許可協議的IL織入器,以Mono.Cecil為基礎構建。

反對IL織入的理由是它需要第三方工具,不能很好地與IDE中運行的靜態分析工具協同,會破壞Edit-and-Continue,降低構建速度。

內部AOP或宏系統

有一些關於某種內部AOP或宏指令的討論。這將允許開發人員擴展語言本身,而不是等待C#的增強。

這次這個選項並沒有得到太多的支持。內部AOP或宏系統會造成整個工具鏈的重大變化。此外,它可能會讓開發人員創建自己的C#方言,造成語言割裂。

什麼也不做

最後一個選項是什麼也不做。最有力的論據是,這僅僅是一個“生活質量”特性,並沒有為開發者提供任何新的東西。雖然減少樣板文件這點值得讚賞,但它們的負面影響超過了其所帶來的好處。

而且,在任何給定的函數中,只需要少量代碼來執行空檢查。

反駁的觀點是,這是C#中最常見的樣板代碼示例之一,在示例和生產代碼中經常缺失。對此,這一選項的支持者給出的回復是,靜態分析工具將檢測出大部分(儘管不是全部)空值檢查的情況。啟用NRT後,靜態分析檢查可以變得更加準確。

原文鏈接:

C# Futures: Simplified Parameter Null Validation