C#7.3 新增功能

C# 7.3 版本有兩個主要主題。 第一個主題提供使安全代碼的性能與不安全代碼的性能同樣好的功能。 第二個主題提供對現有功能的增量改進。 此外,在此版本中添加了新的編譯器選項。html

如下新增功能支持使安全代碼得到更好的性能的主題:編程

  • 無需固定便可訪問固定的字段。
  • 能夠從新分配 ref 本地變量。
  • 能夠使用 stackalloc 數組上的初始值設定項。
  • 能夠對支持模式的任何類型使用 fixed 語句。
  • 能夠使用其餘泛型約束。

對現有功能進行了如下加強:api

  • 能夠使用元組類型測試 == 和 !=
  • 能夠在多個位置使用表達式變量。
  • 能夠將屬性附加到自動實現的屬性的支持字段。
  • 由 in 區分的參數的方法解析獲得了改進。
  • 重載解析的多義狀況如今變得更少。

新的編譯器選項爲:數組

  • -publicsign,用於啓用程序集的開放源代碼軟件 (OSS) 簽名。
  • -pathmap用於提供源目錄的映射。

 

01 啓用更高效的安全代碼

你應可以安全地編寫性能與不安全代碼同樣好的 C# 代碼。 安全代碼可避免錯誤類,例如緩衝區溢出、雜散指針和其餘內存訪問錯誤。 這些新功能擴展了可驗證安全代碼的功能。努力使用安全結構編寫更多代碼。 這些功能使其更容易實現。安全

1.1 索引 fixed 字段不須要進行固定
定義一個結構體
unsafe struct S
{
    public fixed int myFixedField[10];
}

在早期版本的 C# 中,須要固定變量才能訪問屬於 myFixedField 的整數之一。 如今,如下代碼進行編譯,而不將變量 p 固定到單獨的 fixed 語句中:ide

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 語句的文章。性能

1.2 可能會從新分配 ref 局部變量
如今,在對 ref 局部變量進行初始化後,可能會對其從新分配,以引用不一樣的實例。 如下代碼如今編譯:
ref VeryLargeStruct refLocal = ref veryLargeStruct; // 初始化
refLocal = ref anotherVeryLargeStruct;              // 從新分配後,反射引用不一樣的存儲。

有關詳細信息,請參閱有關 ref 返回和 ref 局部變量以及 foreach 的文章。測試

1.3 stackalloc 數組支持初始值設定項
當你對數組中的元素的值進行初始值設定時,你已可以指定該值:
var arr =  new int[3] {1, 2, 3};
var arr2 = new int[] {1, 2, 3};

如今,可向使用 stackalloc 進行聲明的數組應用同一語法:ui

int* pArr = stackalloc int[3] {1, 2, 3};
int* pArr2 = stackalloc int[] {1, 2, 3};
Span<int> arr = stackalloc [] {1, 2, 3};

有關詳細信息,請參閱stackalloc運算符一文。

1.4 更多類型支持 fixed 語句

fixed 語句支持有限的一組類型。 從 C# 7.3 開始,任何包含返回 ref T 或 ref readonly T的 GetPinnableReference() 方法的類型均有可能爲 fixed。 添加此功能意味着 fixed 可與 System.Span<T> 和相關類型配合使用。

有關詳細信息,請參閱語言參考中的 fixed 語句一文。

1.5 加強的泛型約束

如今,能夠將類型 System.Enum 或 System.Delegate 指定爲類型參數的基類約束。

如今也能夠使用新的 unmanaged 約束來指定類型參數必須爲「非託管類型」 。 「非託管類型」 不是引用類型,且在任何嵌套級別都不包含任何引用類型。

有關詳細信息,請參閱有關 where 泛型約束類型參數的約束的文章。

將這些約束添加到現有類型是不兼容的更改。 封閉式泛型類型可能再也不知足這些新約束的要求。

02 提高了現有功能

如下功能提供了對語言中的功能的改進。 這些功能提高了在編寫 C# 時的效率。

2.1 元組支持 == 和 !=

C# 元組類型如今支持 == 和 !=。 有關詳細信息,請參閱有關元組一文中的轉換等式部分。

2.2 將特性添加到自動實現的屬性的支持字段
如今支持此語法:
[field: SomeThingAboutFieldAttribute]
public int SomeProperty { get; set; }

屬性 SomeThingAboutFieldAttribute 應用於編譯器生成的 SomeProperty 的支持字段。 有關詳細信息,請參閱 C# 編程指南中的屬性

2.3 in 方法重載解析決勝屬性
在添加 in 參數修飾符時,這兩個方法將致使多義性:
static void M(S arg);
static void M(in S arg);

如今,經過值(前面示例中的第一個)的重載比經過只讀引用版本的重載更好。 若要使用只讀引用參數調用版本,必須在調用方法前添加 in 修飾符。

有關詳細信息,請參閱有關 in 參數修飾符的文章。

2.4 擴展初始值設定項中的表達式變量
已對在 C# 7.0 中添加的容許 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}");
   }
}
2.5 改進了重載候選項

在每一個版本中,對重載解析規則進行了更新,以解決多義方法調用具備「明顯」選擇的狀況。此版本添加了三個新規則,以幫助編譯器選取明顯的選擇:

  1. 當方法組同時包含實例和靜態成員時,若是方法在不含實例接收器或上下文的狀況下被調用,則編譯器將丟棄實例成員。 若是方法在含有實例接收器的狀況下被調用,則編譯器將丟棄靜態成員。 在沒有接收器時,編譯器將僅添加靜態上下文中的靜態成員,不然,將同時添加靜態成員和實例成員。 當接收器是不明確的實例或類型時,編譯器將同時添加二者。 靜態上下文(其中隱式 this 實例接收器沒法使用)包含未定義 this 的成員的正文(例如,靜態成員),以及不能使用 this 的位置(例如,字段初始值設定項和構造函數初始值設定項)。
  2. 當一個方法組包含類型參數不知足其約束的某些泛型方法時,這些成員將從候選集中移除。
  3. 對於方法組轉換,返回類型與委託的返回類型不匹配的候選方法將從集中移除。

你將注意到此更改,由於當你肯定哪一個方法更好時,你將發現多義方法重載具備更少的編譯器錯誤。

03 新的編譯器選項
新的編譯器選項支持 C# 程序的新版本和 DevOps 方案。
3.1 公共或開放源代碼簽名

-publicsign 編譯器選項指示編譯器使用公鑰對程序集進行簽名。 程序集被標記爲已簽名,但簽名取自公鑰。 此選項使你可以使用公鑰在開放源代碼項目中構建簽名的程序集。

有關詳細信息,請參閱 -publicsign 編譯器選項一文。

3.2 pathmap

-pathmap 編譯器選項指示編譯器將生成環境中的源路徑替換爲映射的源路徑。 -pathmap 選項控制由編譯器編寫入 PDB 文件或爲 CallerFilePathAttribute 編寫的源路徑。

有關詳細信息,請參閱 -pathmap 編譯器選項一文。

 

相關文章
相關標籤/搜索