C# 已經跟著 .NET 6 一起獲得了更新到了第十版了,這邊來介紹一下C# 10有哪些新玩意的筆記
這邊要說明一下 C# 10會跟著 Visual Studio 2022 ( 要有安裝 .NET 6 ) 一同使用喔! 但是如果是獨立安裝的也可以用 Visual Studio Code or Visual Studio for Mac使用喔!
接著就是小筆記的時間拉
record improvement
先前的時候使用 record 基本上就只需要用以下程式碼就可以
record Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
}
但是這樣的 record 其實依然是 class ( reference type )
而這次介紹了 record struct 只需要把上方的程式碼改成如下就可以變成struct
record struct Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
}
這樣可以把 init 這樣的修飾詞也讓 struct 也能使用到! 當然除了 class 和 struct 在記憶體上的allocation的地方不同之外最大的特性就是可不可以用 == ( 比較子 )做比較!如以下的Code
var person = new Person { FirstName = "F", LastName = "La" };
var anotherPerson = new Person { FirstName = "AnF", LastName = "AnLa" };
Console.WriteLine( person == anotherPerson ); // If not C# 10 will get the error!
Anonymous type improvement
在很早之前 C# 就已經支援匿名型別,但是這次更新讓匿名型別能夠支援其他新的語法,比如如下的語法
var person = new
{
FirstName = "F",
LastName = "La"
};
var another = person with { LastName = "AnLA" };
Custom parameterless constructor for struct
假設沿用上面的程式碼,Person是使用stuct來撰寫那麼以下程式碼的執行結果如果在 C# 10以前會是一樣的.
Person p1 = default;
Person p2 = new();
但是在C# 10開始可以支援讓 Struct 也能夠使用 custom parameterless constructor 如下所示
struct Person
{
public Person()
{
FirstName = "LOL";
LastName = "Oops";
}
public string FirstName { get; init; }
public string LastName { get; init; }
}
要使用這功能的時候 建構子必須是要公開的 !這樣的話使用 new() 所產生的 p2 就不會等同於 p1! default 就是當作用預設值所以 p1的 FirstName, LastName 都會是 default 值而 string 的 default 值就是 null. 所以 C# 10要特別小心關於 struct 有沒有使用 custom parameterless constructor的功能.然後也可以改寫成如下的程式碼
struct Person
{
public string FirstName { get; init; } = "LOL";
public string LastName { get; init; } = "Oops";
}
這樣compiler就會幫你長一個public custom parameterlesse constructor出來!
File-scoped namespace and declaration
這個功能基本上直接看程式碼最清楚拉,如下所示
namespace Model
{
struct Person
{
public string FirstName { get; init; } = "LOL";
public string LastName { get; init; } = "Oops";
}
}
在C# 10就可以簡單變成以下的程式碼
namespace Model;
struct Person
{
public string FirstName { get; init; } = "LOL";
public string LastName { get; init; } = "Oops";
}
直接把命名空間括號給拿掉拉~有的時候要對齊括號真的很讓人頭痛,雖然有很多好工具可以使用但簡化了一些括號是不錯的調整.
Global using directives
這個功能好處就是可以把很多 .cs 檔案的 using namespace 的功能讓所有的 .cs 檔案共同使用.所以可以建立個 globalusing.cs檔案( 檔案名稱不限拉,這只是我個人命名方式 ) 並放入以下程式碼
global using System;
global using System.Linq;
global using System.Threading.Tasks;
這個功能是在 project 中的所有 .cs 檔案都適用喔
Implicit using directives
這個功能也是可以讓 使用命名空間( using System; ) 這樣的寫法變得更加好用,在 csproject 中可以加入以下語法
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
或是使用 Visual Studio 2022的專案屬性然後,搜尋 using 就可以找到該選項.
這樣在該專案中的所有 .cs 檔案都可以不用使用屬於該專案類型內建的namespace,所以 Console app 的專案類型來說 System 開頭的命名空間都可以不需要加入到 .cs 檔案中了!但是如果有 static using 的命名空間除外.
Lamda improvement
關於 Lamda在 C# 也是很常用的語法,尤其在寫 delegate 等延伸的 class 的時候非常常使用到!以下的程式碼來看看差異吧
Func<string, int> convertToInt1 = new Func<string, int>(str => int.Parse(str));
Func<string, int> convertToInt2 = (string str) => int.Parse(str);
var convertToInt3 = (string str) => int.Parse(str); // C# 10
透過足夠的資訊可以推倒傳入值為string 輸出值為int 的lamda expression. 然後以下是個情境
Func<bool, object> choose = (bool b) => b ? 1 : "Oops";
這時候如果把 choose 的型別改寫成 var 就得要告訴 compiler 回傳值的型別,所以就可以寫成以下程式碼
var choose = object (bool b) => b ? 1 : "Oops";
甚至可以加上 C# Attribute
var choose = [MyAttribute] object (bool b) => b ? 1 : "Oops";
Type inference for lamdas and method groups
以下是使用 Method Group的程式碼,說真的應該沒有多少人會想要這樣寫吧…
Func<int> read = Console.Read;
Action<string> write = Console.Write;
然後可以改寫成
var read = Console.Read;
var write = Console.Write; // Not working
之所以Write不能用是因為Console.Write有高達16個 method overload所以 compiler 無法判斷出回傳的型別為何,但Console.Read只有一個所以可以推倒出型別!
Interpolated string performance optimization
基本上我們一般寫程式碼都會使用到 string,兒 interpolated string 也就是這個用法,請看下方程式碼
var myName = "James";
var myAge = 4;
Console.WriteLine($"Name => {myName}, Age => {myAge}";
這樣的程式碼在compiler底下還是去呼叫了stringbuilder所以如果是以下程式碼問題就慢慢大條了
var myAge = 4;
var sb = new StringBuilder();
sb.Append($"My age is {myAge}!";
已經使用 StringBuilder 的情況下又去使用 interpolated string 那就是在底下又去產生另一個 StringBuilder!
像是常見的問題點如下程式碼所示
public void DebugAsset(bool condition)
{
Debug.Asset(true,$"{DateTime.Now} - {DoCalculate()}");
}
private string DoCalculate()
{
// DO something
return string.Empty;
}
這個功能是實作在compiler的進一步的優化,如果想要寫自己的優化步驟可以參考以下連結
$ - string interpolation - C# reference | Microsoft Docs
Explore string interpolation handlers | Microsoft Docs
心得
現在C# 10 的很多新的設計也是在簡化很多當初先前版本遺留的問題,像是在 Asp .NET 6 minial API 就是因為有以上新的特性才能讓整個專案的 cs 檔案的行數不到50行就能達成,當然相關的像是 Entity Framework Core 也是有受惠到這些新特性.基本上看看團隊最大的問題是否能夠透過修改成 C# 10的特性能夠讓團隊開發更加的有效率!
相關參考連結