C# 7.3 版本有兩個主要主題。 第一個主題提供使安全代碼的性能與不安全代碼的性能一樣好的功能。 第二個主題提供對現有功能的增量改進。 此外,在此版本中添加了新的編譯器選項。
以下新增功能支持使安全代碼獲得更好的性能的主題:
- 無需固定即可訪問固定的字段。
- 可以重新分配
ref本地變量。 - 可以使用
stackalloc數組上的初始值設定項。 - 可以對支持模式的任何類型使用
fixed語句。 - 可以使用其他泛型約束。
對現有功能進行了以下增強:
- 可以使用元組類型測試
==和!=。 - 可以在多個位置使用表達式變量。
- 可以將屬性附加到自動實現的屬性的支持字段。
- 由
in區分的參數的方法解析得到了改進。 - 重載解析的多義情況現在變得更少。
新的編譯器選項為:
-publicsign,用於啟用程序集的開放源代碼軟件 (OSS) 簽名。-pathmap用於提供源目錄的映射。
你應能夠安全地編寫性能與不安全代碼一樣好的 C# 代碼。 安全代碼可避免錯誤類,例如緩沖區溢出、雜散指針和其他內存訪問錯誤。 這些新功能擴展了可驗證安全代碼的功能。努力使用安全結構編寫更多代碼。 這些功能使其更容易實現。
unsafe struct S { public fixed int myFixedField[10]; }
在早期版本的 C# 中,需要固定變量才能訪問屬於 myFixedField 的整數之一。 現在,以下代碼進行編譯,而不將變量 p 固定到單獨的 fixed 語句中:
class C { static S s = new S(); unsafe public void M() { int p = s.myFixedField[5]; } }
變量 p 訪問 myFixedField 中的一個元素。 無需聲明單獨的 int* 變量。 請注意,你仍然需要 unsafe 上下文。 在早期版本的 C# 中,需要聲明第二個固定的指針:
class C { static S s = new S(); unsafe public void M() { fixed (int* ptr = s.myFixedField) { int p = ptr[5]; } } }
有關詳細信息,請參閱有關 fixed 語句的文章。
ref 局部變量進行初始化后,可能會對其重新分配,以引用不同的實例。 以下代碼現在編譯:
ref VeryLargeStruct refLocal = ref veryLargeStruct; // 初始化 refLocal = ref anotherVeryLargeStruct; // 重新分配后,反射引用不同的存儲。
有關詳細信息,請參閱有關 ref 返回和 ref 局部變量以及 foreach 的文章。
var arr = new int[3] {1, 2, 3}; var arr2 = new int[] {1, 2, 3};
現在,可向使用 stackalloc 進行聲明的數組應用同一語法:
int* pArr = stackalloc int[3] {1, 2, 3}; int* pArr2 = stackalloc int[] {1, 2, 3}; Span<int> arr = stackalloc [] {1, 2, 3};
有關詳細信息,請參閱stackalloc運算符一文。
fixed 語句支持有限的一組類型。 從 C# 7.3 開始,任何包含返回 ref T 或 ref readonly T的 GetPinnableReference() 方法的類型均有可能為 fixed。 添加此功能意味着 fixed 可與 System.Span<T> 和相關類型配合使用。
有關詳細信息,請參閱語言參考中的 fixed 語句一文。
現在,可以將類型 System.Enum 或 System.Delegate 指定為類型參數的基類約束。
現在也可以使用新的 unmanaged 約束來指定類型參數必須為“非托管類型” 。 “非托管類型” 不是引用類型,且在任何嵌套級別都不包含任何引用類型。
有關詳細信息,請參閱有關 where 泛型約束和類型參數的約束的文章。
將這些約束添加到現有類型是不兼容的更改。 封閉式泛型類型可能不再滿足這些新約束的要求。
以下功能提供了對語言中的功能的改進。 這些功能提升了在編寫 C# 時的效率。
[field: SomeThingAboutFieldAttribute] public int SomeProperty { get; set; }
屬性 SomeThingAboutFieldAttribute 應用於編譯器生成的 SomeProperty 的支持字段。 有關詳細信息,請參閱 C# 編程指南中的屬性。
in 參數修飾符時,這兩個方法將導致多義性:
static void M(S arg); static void M(in S arg);
現在,通過值(前面示例中的第一個)的重載比通過只讀引用版本的重載更好。 若要使用只讀引用參數調用版本,必須在調用方法前添加 in 修飾符。
有關詳細信息,請參閱有關 in 參數修飾符的文章。
out 變量聲明的語法進行了擴展,以包含字段初始值設定項、屬性初始值設定項、構造函數初始值設定項和查詢子句。 它允許使用如以下示例中所示的代碼:
public class B { public B(int i, out int j) { j = i; } } public class D : B { public D(int i) : base(i, out var j) { Console.WriteLine($"The value of 'j' is {j}"); } }
在每個版本中,對重載解析規則進行了更新,以解決多義方法調用具有“明顯”選擇的情況。此版本添加了三個新規則,以幫助編譯器選取明顯的選擇:
- 當方法組同時包含實例和靜態成員時,如果方法在不含實例接收器或上下文的情況下被調用,則編譯器將丟棄實例成員。 如果方法在含有實例接收器的情況下被調用,則編譯器將丟棄靜態成員。 在沒有接收器時,編譯器將僅添加靜態上下文中的靜態成員,否則,將同時添加靜態成員和實例成員。 當接收器是不明確的實例或類型時,編譯器將同時添加兩者。 靜態上下文(其中隱式
this實例接收器無法使用)包含未定義this的成員的正文(例如,靜態成員),以及不能使用this的位置(例如,字段初始值設定項和構造函數初始值設定項)。 - 當一個方法組包含類型參數不滿足其約束的某些泛型方法時,這些成員將從候選集中移除。
- 對於方法組轉換,返回類型與委托的返回類型不匹配的候選方法將從集中移除。
你將注意到此更改,因為當你確定哪個方法更好時,你將發現多義方法重載具有更少的編譯器錯誤。
-publicsign 編譯器選項指示編譯器使用公鑰對程序集進行簽名。 程序集被標記為已簽名,但簽名取自公鑰。 此選項使你能夠使用公鑰在開放源代碼項目中構建簽名的程序集。
有關詳細信息,請參閱 -publicsign 編譯器選項一文。
-pathmap 編譯器選項指示編譯器將生成環境中的源路徑替換為映射的源路徑。 -pathmap 選項控制由編譯器編寫入 PDB 文件或為 CallerFilePathAttribute 編寫的源路徑。
有關詳細信息,請參閱 -pathmap 編譯器選項一文。
