在之前的C# 7 新特性博客中,我們談到了Tuples,Record Type和Pattern Matching。這些都是C#新特性中最可能出現的。在本博客中,我們會提到更多的一些特性,雖然這些特性不像之前的有那么多的關注,但也是很有用的特性。
來源https://www.kenneth-truyers.net/2016/01/25/new-features-in-c-sharp-7-part-2/?utm_campaign=C%23%2BWeekly&utm_medium=email&utm_source=C%23_Weekly_44
Non-nullable引用類型##
What###
c#2.0中引入了可空值類型,本質上它是Nullable
Why###
空引用一直被稱之為"The billion dollar mistake"(Tony Hoare)。NullReference異常太常見了。問題是有兩方面的,要么你沒有檢測null值,造成運行時異常;要么你檢查了他們,你的的代碼變成了垃圾堆,充斥着檢測null的代碼,而卻缺少真正需要的語句。聲明一個不可為null的引用類型可以克服這個問題。
How###
注意:下面的語法是尚未確定下來的,仍可能變動。目前有各種各樣的提議,所以不清楚具體的形式會是什么樣子。當我提到"error"時,尚不清楚是兼容性錯誤還是只是warning。
首先,最理想的做法是,引用類型默認為Non-nullable的,這樣可以和值類型的默認也是Non-nullable相對應,如下。
int a; //non-nullable value type
int? b; //nullable value type
string c; //non-nullable reference type
string? d; //nullable reference type
然而,這種做法兼容性非常不好。之前存在的數百萬千萬行代碼,會因為引用類型默認為Non-nullable而break。所以必須使用不同的方式,以滿足向前兼容。目前提議的做法如下。
int a; //non-nullable value type
int? b; //nullable value type
string! c; //non-nullable reference type
string d; //nullable reference type
使用nullbale類型和Non-nullable類型會影響編譯器。
MyClass a; // Nullable reference type
MyClass! b; // Non-nullable reference type
a = null; // OK, this is nullable
b = null; // Error, b is non-nullable
b = a; // Error, n might be null, s can't be null
WriteLine(b.ToString()); // OK, can't be null
WriteLine(a.ToString()); // Warning! Could be null!
if (a != null) { WriteLine(a.ToString); } // OK, you checked
WriteLine(a!.Length); // Ok, if you say so
這種語法兼容性是沒問題的,但是對於泛型卻會有問題。
/ The Dictionary is non-nullable but string, List and MyClass aren't
Dictionary<string, List<MyClass>>! myDict;
// Proper way to declare all types as non-nullable
Dictionary<string!, List<MyClass!>!>! myDict;
如上,卻不便於閱讀。一種簡便的形式如下。
// Typing ! in front of the type arguments makes all types non-nullable
Dictionary!<string, List<MyClass>> myDict;
局域函數local functions##
What###
允許你在區域作用域內聲明方法和類型。
Why###
通過Func和Action匿名方法在一定程度上可以這么做。但是這樣缺少一些特性,如下
- 泛型
- **ref和out參數
- params
How###
public int Calculate(int someInput)
{
int Factorial(int i)
{
if (i <= 1)
return 1;
return i * Factorial(i - 1);
}
var input = someInput + ... // Other calcs
return Factorial(input);
}
不可變類型##
What###
不可變對象是在對象創建之后,其狀態不能被修改。
Why###
不可變對象有如下好處:
- 天生的線程安全
- 更容易使用和推測代碼
- 更方便並行編程
- 不可變類型可以緩存,因為他們不會改變
目前,也是有可能去聲明不可變對象的,如下
public class Point
{
public Point(int x, int y)
{
x = x;
Y = y;
}
public int X { get; }
public int Y { get; }
}
如上雖然聲明定義了不可變對象,但是其意圖卻是不明顯的。也許某一天有人對其添加了setter,那對其他的使用者來說,就會有不一樣的結果。
How###
注意:再一次說明,如下語法是尚未固定的。初始的提案是添加immutable關鍵字。
public immutable class Point
{
public Point(int x, int y)
{
x = x;
Y = y;
}
public int X { get; }
public int Y { get; }
}
當有了不可變類型之后,在語言上就可以支持基於不同的一個實例來創建一個新的實例,如下。
var a = new Point(2, 5);
var b = a with { X = 1};
總結##
如上所述,仍是C# 7的早期階段,如上語法很有可能會變。但是這些特性非常令人exciting的,也會使C#編程變得更愉悅。鼓勵大家去Github上去看有關特性的目前的討論情形。