整理常用的
C# 2.0 版 - 泛型 , partial class , delegate (Func) , 可為 null 的C#實數值型別 (int?) , yield return
C# 3.0 版 - LINQ , 擴充方法 , 自動實作的屬性 , 匿名類型 var v = new { Amount = 108, Message = "Hello" };
, 物件和集合初始設定式
C# 4.0 版 - 動態型別 (dynamic) , 具名和選擇性引數 ,
C# 5.0 版 - async await ,
C# 6.0 版 - nameof , 唯讀 Auto 屬性 , Null 條件運算子 first = person?.FirstName ?? "Unspecified";
, $"{FirstName} {LastName}"
, 例外狀況篩選條件
使用索引子初始化關聯集合
private Dictionary<int, string> webErrors = new Dictionary<int, string>
{
[404] = "Page not Found",
[302] = "Page moved, but left a forwarding address.",
[500] = "The web server can't come out to play today."
};
C# 7.0 版 - out 變數 if (int.TryParse(input, out var answer))
,
Tuples
(string Alpha, string Beta) namedLetters = ("a", "b");
public class Point
{
public Point(double x, double y)
=> (X, Y) = (x, y);
public double X { get; }
public double Y { get; }
public void Deconstruct(out double x, out double y) =>
(x, y) = (X, Y);
}
Discard - 暫存虛擬變數 (_, _, area) = city.GetCityInformation(cityName);
模式比對 - is 運算式
if (input is int count) sum += count;
模式比對 - switch 比對運算式
public static int SumPositiveNumbers(IEnumerable<object> sequence)
{
int sum = 0;
foreach (var i in sequence)
{
switch (i)
{
case 0:
break;
case IEnumerable<int> childSequence:
{
foreach(var item in childSequence)
sum += (item > 0) ? item : 0;
break;
}
case int n when n > 0:
sum += n;
break;
case null:
throw new NullReferenceException("Null found in sequence");
default:
throw new InvalidOperationException("Unrecognized type");
}
}
return sum;
}
C# 8.0 版 (C# .Net Core 3.x 和 .NET Standard 2.1支援8.0) -
Nullable Reference Types Huan-Lin 學習筆記
編譯時幫你檢查null reference 的可能性有的話跳警告
定義一個屬性string Title 會警告 可能為null
如果就是可能為null時要string? 這樣編譯器就知道這是可能為null 不會跳警告
class 給預設初始值
post.title!.Length 只是跟編譯器說這裡不會有null 的時候讓編譯器不要跳警告
Pattern matching 進一步強化,其中包含:
1. Switch 運算式 (Switch Expressions)
2. 屬性模式 (Property Pattern)
3. Tuple 模式 (Tuple Pattern)
4. 位置模式 (Positional Pattern)
C# 8 索引(Indices)與範圍(Ranges)
兩個新的類型(Index, Range)與兩個新的運算子(^, ..)
System.Index 序列索引
^ 序列結尾開始
System.Range 序列子範圍。
.. 指定範圍 開始結束
C# 9.0 initial only property
public string Name { get; init; }
init就是 property setter,僅能在物件初始化設定式中設定此屬性值
C# 9.0 record
record 是一個糖分非常高的語法糖
(1) implement IEquatable<T> interface
(2) override void Equals(Object other) 方法,內容則為呼叫 this.Equals(other as Person)。
(3) overload == 和 != 運算子,讓這兩個運算子的行為和 Equals 方法一致。
(4) override int GetHashCode() 方法。
(5) 如果沒有手動寫建構式的話,編譯器會產生兩個建構式,一個是無參數建構式 (這是原本編譯器處理類別的行為,和 record 無關);另外一個是具有自身型別為參數的建構式,若為編譯器產出的這個建構式存取修飾會被宣告為 protected。
(6) 產生一個 public virtual Person <Clone>$() 方法,這個方法的內部會呼叫 new Person(this) 回傳一個新的執行個體,這個方法不能直接在 C# 使用程式碼直接呼叫,必須透過新的 with expression 來使用。
(7) 產生一個唯讀的屬性 protected virtual Type EqualityContract,內容很簡單,就是 return typeof(Person); 。
(8) 加入一個 protected virtual bool PrintMembers(StringBuilder builder) 方法,這個方法的內容是串聯欄位與屬性值字串,基本上是為了給 ToString() 方法呼叫。
(9) override ToString() 方法。
var p1 = new Person { id = 10, Age = 28, Name = "Bill" };
var p2 = p1 with { id = 11, Name = "Tom" };
p2 會指向一個新的執行個體,這個執行個體的 id 欄位會被改變為 11,Name 屬性則會變更成 "Tom";
預設生成的是屬性是 {get;init;} 不是 {get;set;},這代表設定值時間點在 constructor(建構式),延伸產生immutable(不可變)特性,也代表 record 預設為thread-safe(線程安全)
注意不能把 record 當作一定是 immutable(不可變),原因在微軟沒有限制以下寫法
准許修改 {get;init;} 為 {get;set},將會導致 immutable 跟 thread-safe 特性消失
參考資料
C# 的歷史
如果內容有誤請多鞭策謝謝