C# 14 新功能 其他

C# 14 新功能還有一些比較無法長篇描述的就集中在這裡一次說完。

null-conditional assignment

在 C# 6.0 的新功能中 null conditional operator 是非常重要的一步,這使得我們可以不需要為了檢查是否為 null 而寫出一大串的判斷式,例如你以前可能需要這樣寫:

  if (person != null && person.Address != null )
  {
      var city = person.Address.City;
  }

在 C# 6.0 之後就能簡化成:

 var city = person?.Address?.City;

但是,就是這個但是,當時 null conditional operator 沒有辦法放在指派運算子的左邊,這功能終於在 C# 14 完善了,現在我可以大膽地這樣寫:

person?.Address?.City = "taipei";
nameof supports unbound generic types

這個功能簡單解釋就是以前要使用 nameof 運算式取得泛型型別名稱的時候,泛型參數必須是 close type,例如:

var c1 = nameof(List<int>); // c1 is "List"

C# 14 則可以使用 open type

var c2= nameof(List<>); // c2 is "List"

看起來很廢,但具有幾個重要的意義:

  1. 不需要為了 nameof 硬是填一個不相干的型別進泛型參數,在意圖上的表達較為明確
  2. 和 typeof 表達式一致,typeof 本來就可以使用 open type 
  3. 有一個比較特殊的情境是假設是自訂了一個名為 MyList<T> 泛型類別,而你在程式碼中使用了 nameof(MyList<int>);過了不久後你的同事將 MyList 的泛型參數加入約束為參考型別,那你所有使用 nameof(MyList<int>) 的程式碼都會從正常變成編譯錯誤,如果使用 nameof(MyList<>) 就能避免這類問題。
Modifiers on simple lambda parameters

進一步簡化 Lambda,過往 Lambda 的參數遇到修飾詞的時候必須要明確地宣告參數型別,這一次改善這個問題,例如

 delegate bool TryParse<T>(string s, out T result);
 delegate void SpanAction(scoped ReadOnlySpan<char> span);
 delegate void ReadOnlyRefAction<T>(ref readonly T value);

 internal class Program
 {
     static void Main(string[] args)
     {
         TryParse<int> tryParse = (text, out result) => int.TryParse(text, out result);
         SpanAction print = (scoped x) => Console.WriteLine(x.Length);
         ReadOnlyRefAction<int> write = (ref readonly x) => Console.WriteLine(x);
     }      
 }

目前可以省略參數型別的修飾詞有 ref、out、in、scoped 與 ref readonly,至於 params 截至目前還是需要明確宣告其陣列型別。

Implicit span conversions

這是一個比較不容易感受的改變,沒錯,它就是要讓你不容易感受。

這個功能簡單來說,就是將轉型為 Span<T> 或  ReadOnlySpan<T> 的行為從 API 層級升等到編譯器層級。例如有以下兩個擴充方法,其參數分別為 ReadOnlySapn<char> 與 ReadOnlySpan<T>:

    public static class MyExtensions
    {
        public static void Display(this ReadOnlySpan<char> span)
        {
            for (int i = 0; i < span.Length; i++)
            {
                Console.Write(span[i]);
            }
            Console.WriteLine();
        }

        public static void Show<T>(this Span<T> span)
        {
            foreach (var item in span)
            {
                Console.Write($"{item} ");
            }
            Console.WriteLine();
        }
    }

先看呼叫 Display 方法的過去與現在:

 string text = "Hello, World!";
 text.AsSpan().Display(); // 過去,需要先轉換為 ReadOnlySpan<char>,
 text.Display(); // 現在,可以直接呼叫擴充方法,編譯器會處理轉換為 ReadOnlySpan<char> 的程序

呼叫 Show 方法的過去與現在:

 /* 過去, 必須先轉換為 ReadOnlySpan<int> */
 var array = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 ReadOnlySpan<int> readOnlySpan = array;
 readOnlySpan.Show();

 /* 現在,可以直接呼叫擴充方法,編譯器會處理轉換為 ReadOnlySpan<char> 的程序 */
 array.Show();

C# 14 的新功能就介紹到這篇,下次見。