如何掌握C#的核心技術
引子
前不久看到一個段子,某年寧波交警引進人臉識別技術抓拍行人闖紅燈,結果一天下來被發現闖紅燈次數最多的是珠海女子董小姐,日闖紅燈3000多次。寧波交警連夜研究抓捕方案,最後分析發現,原來是大巴車上的某掌握核心的產品廣告被錯誤識別了。
這家自稱掌握了核心的製造企業,雖然並非每個產品都賣座,但這樣的廣告詞確實也牢牢抓住了觀眾的眼球,簡單明瞭的廣告詞,使產品具備更加鮮明的標籤,形成了其獨特的品牌形象。
最近,又看到某汽車製造大廠,雖然業績不怎麼樣,但其董事長的眼界之高令人欽佩。在股東會上,有股東詢問過去業績不佳,是否有興趣在無人駕駛技術上跟某民族品牌建立進一步合作關係時,這位董事長也毫不猶豫的回答到:
“不接受xx提供的無人駕駛整體解決方案,要將核心技術掌握在自己手中。“
至於這家公司是否真的掌握了核心技術,也許有讀者作為該公司的產品使用者,或汽車產業從業人員,或甚至是股東,可能比較清楚,小編比較菜,對這種核心技術不太瞭解。
但小編從這兩個案例發現了一個現象,核心技術無論對於公司而言,還是對於個人而言,都是非常有價值的關鍵特性。一個掌握了核心技術的開發者,必然是脫離了低階趣味的專業開發者,在紛繁複雜的網際網路時代面前,往往有更多機會凸顯自己的才華,進而獲得與自己實力相匹配的待遇水平。
毫無疑問,掌握C#的核心技術也同樣如此。那麼,問題是,C#的核心技術有哪些呢?我們該如何掌握C#的核心技術呢?
C#的發展歷程
眾所周知,C#是由偉大的程式設計師之神Anders Hejlsberg為體現.NET技術的優勢而創造出來的一種優秀語言。說起Anders Hejlsberg雖然可能有的讀者不太熟悉,但說起他創造的幾種語言或編譯器,大家估計就並不陌生了。
例如他20歲時花了僅僅兩三週就開發出來了一種Pascal編譯器。之後他又開發出了Delphi,這是一種非常神奇的語言,在程式導向式開發方法的時代,Delphi能夠與VB獨佔半邊天,其優秀之處顯然不是區區幾句話就能說清楚,聽說在當時,許多開發者都非常擅長使用其創造奇蹟,例如今天的產品之神張小龍在30年前就曾經用其開發過foxmail,早期的wps據說也是使用Delphi開發出來的。
再後來,Anders加入了微軟,併為.NET設計了C#這樣一款優秀的語言。(當然,Anders並未止步於C#這樣的成就,在C#之後,他又改良了Javascript,併為其帶來了今天的“後端噩夢”TypeScript語言。)
2002年,C#隨.NET戰略一起釋出,從一開始就被定位為.NET開發框架核心中的核心,直到今天,已經成為一種比較優秀的主流技術語言。這種語言吸收了其他語言的優勢,同時又基於.NET框架的特性實現了許多優雅的功能,今天的C#,不僅僅能夠用於傳統的物件導向開發,也同樣可以廣泛使用於函式式開發方法。對於初學者而言,如果學過Java和C++語言,上手也非常容易。
經過將近20年的發展,C#語言已經迭代了15個主要版本,從最早期的C#1.0到現在最新版的9.0,及10.0預覽版,共釋出了6次正式版本釋出,對於許多開發者而言,每一次版本升級也意味著又需要重新整理技術面,著實是一種痛並快樂的過程。
回顧那麼多個版本,你還記得哪些C#的“核心技術”給你帶來過開發效率的巨大提升麼?
《C#的核心技術指南》中的核心技術
最近,我有幸閱讀了新出版的《C#8.0核心技術指南》,並在這篇文章中,我摘取了幾個C#相關的新特性和概念跟大家一起分享。當然由於C#實際上是.NET框架的主力語言,以下介紹的一些核心技術,可能實質上是.NET框架的核心技術,大家不用糾結這個問題。
C#9.0新特性
參見https://docs.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-9。
C#8.0的新特性
參見https://docs.microsoft.com/zh-cn/dotnet/csharp/whats-new/csharp-8
C#可為空型別
3.1 可為空值型別
可為空值型別是針對基礎型別而言,例如Int? bool?double?這些基礎型別都是我們常用的可為空值型別,該型別出現得比較早,在C#2.0中就已經出現了可為空值型別。
檢查可為空值型別的例項
從C#7.0開始,可以使用is表示式對可為空值型別進行檢查,
int? a = 42;
if (a is int valueOfA)
{
Console.WriteLine($"a is {valueOfA}");
}
else
{
Console.WriteLine("a does not have a value");
}
// Output:
// a is 42
當然,依然可以使用HasValue這種型別對可為空值型別進行檢查。
3.2 C#可為空引用型別
可為空值型別常用於資料庫的檢查中,可以通過該型別判斷物件是否為空,而可為空引用型別則恰好相反,可以一定程度上防止引用型別的值為空,避免引發 “未將物件引用新增到物件的例項”這樣的空指標異常。
該型別自C#8.0 引入,包括兩種方式“可為空引用型別”和“不可為空引用型別”,使你能夠對引用型別變數的屬性作出重要宣告 :
- 引用不應為 null。 當變數不應為 null 時,編譯器會強制執行規則,以確保在不首先檢查它們是否為 null 的情況下,取消引用這些變數是安全的:
- 必須將變數初始化為非 null 值。
- 變數永遠不能賦值為
null
。
- 引用可為 null。 當變數可以為 null 時,編譯器會強制執行不同的規則以確保你已正確檢查空引用:
- 只有當編譯器可以保證該值不為 null 時,才可以取消引用該變數。
- 這些變數可以使用預設的
null
值進行初始化,也可以在其他程式碼中賦值為null
。 型別為 Null 性
例如,在常用的語句中,我們可能這樣實現:
void foo(string? s)=>Console.WriteLine(s.Length);
一旦出現了string為空的情況,可能很容易就會引發空指標異常。
可為空上下文
可為空上下文可以對編譯器如何解釋引用型別變數進行精細控制。
可以使用 .csproj 檔案中的 Nullable
元素為專案設定可為空註釋上下文和可為空警告上下文。 此元素配置編譯器如何解釋型別的為 Null 性以及生成哪些警告。 有效設定如下:
-
enable
:“啟用”可為空註釋上下文。 “啟用”可為空警告上下文。
- 引用型別的變數,例如
string
是“不可為空”。 啟用所有為 Null 性警告。
- 引用型別的變數,例如
-
warnings
:“禁用”可為空註釋上下文。 “啟用”可為空警告上下文。
- 引用型別的變數是“無視”。 啟用所有為 Null 性警告。
-
annotations
:“啟用”可為空註釋上下文。 “禁用”可為空警告上下文。
- 引用型別的變數(例如字串)不可為 null。 禁用所有為 Null 性警告。
-
disable
:“禁用”可為空註釋上下文。 “禁用”可為空警告上下文。
- 引用型別的變數是“無視”,就像早期版本的 C# 一樣。 禁用所有為 Null 性警告。
示例:
XML複製
<Nullable>enable</Nullable>
你還可以使用指令在專案的任何位置設定這些相同的上下文:
#nullable enable
:將可為空註釋上下文和可為空警告上下文設定為“已啟用”。#nullable disable
:將可為空註釋上下文和可為空警告上下文設定為“已禁用”。#nullable restore
:將可為空註釋上下文和可為空警告上下文還原到專案設定。#nullable disable warnings
:將可為空警告上下文設定為“已禁用”。#nullable enable warnings
:將可為空警告上下文設定為“已啟用”。#nullable restore warnings
:將可為空警告上下文還原到專案設定。#nullable disable annotations
:將可為空註釋上下文設定為“禁用”。#nullable enable annotations
:將可為空註釋上下文設定為“啟用”。#nullable restore annotations
:將註釋警告上下文還原到專案設定。
屬性模式
C#在7.0中引入了屬性模式,通過該模式,可以快速匹配物件的一個或多個屬性值。例如,我們可以使用這樣的示例快速匹配相關屬性值。
if (obj is string s && s.Length=4)
除了這種屬性模式,還有一種是C#8.0中引入的模式,該模式主要用於switch語句的用法,使用起來也非常簡潔。
bool ShouldAllow(Url url)=>url switch
{
{Scheme:"http",Port=80}=>true,
{Scheme:"https",port=443}=>true
}
屬性模式還支援巢狀,例如
bool ShouldAllow(Url url)=>url switch
{
{Scheme:string{Length:4},Port=80}=>true,
{Scheme:"https",port=443}=>true
}
甚至支援使用when子句。例如:
{Scheme:"http",Port:80} when url.Host.Length<1000=>true,
這樣的寫法可以使我們部分邏輯程式碼變得更加精簡,看起來更有逼格。
屬性還提供了元組模式,位置模式兩種模式,元組模式提供了切換多個值的簡單機制,而位置模式則定義了使用物件的位置屬性作為匹配模式的方式。
以下是官方文件關於位置模式的示例。
public readonly struct Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y) => (X, Y) = (x, y);
public void Deconstruct(out int x, out int y) => (x, y) = (X, Y);
}
static string Classify(Point point) => point switch
{
(0, 0) => "Origin",
(1, 0) => "positive X basis end",
(0, 1) => "positive Y basis end",
_ => "Just a point",
};
不過,官方文件並沒有介紹元組模式的示例,而《C#8.0核心技術指南》中介紹了該模式的用法,大家可以從書中獲取相關知識。
Json處理
過去,我們傾向於使用Json.NET來處理C#中的Json序列化問題,而現在,我們則可以依託官方庫Sytem.Text.Json來完成。(雖然我們有時可能不願意用,但往後官方的許多方法會更多的依賴該庫來實現)。相比json.net,該官方庫的主要優點是更簡單、高效並且記憶體使用效率更高。
官方庫提供瞭如下幾種操作形式:
1、Utf8JsonReader:這是一種優化的前向Json讀取器,用於讀取Utf8編碼的Json文字。
2、Uft8JsonWriter:這是一種Json輸出器,可用於輸出Utf8編碼Json文字。
3、JsonDocument:該型別可以將Json資料解析為只讀的DOM,可以用類似於XMLDocument的方式操作延遲載入的JsonElement示例。同時,也可以用JsonDocument讀取物件,並使用Json寫入器對Json進行更新。
Span和Memory
Span
SpanSpan<T>
是在堆疊上分配的 引用結構 ,而不是在託管堆上分配的。
Span<T>
表示任意記憶體的連續區域。以下為官方文件提供的示例:
// Create a span over an array.
var array = new byte[100];
var arraySpan = new Span<byte>(array);
byte data = 0;
for (int ctr = 0; ctr < arraySpan.Length; ctr++)
arraySpan[ctr] = data++;
int arraySum = 0;
foreach (var value in array)
arraySum += value;
Console.WriteLine($"The sum is {arraySum}");
// Output: The sum is 4950
由於 Span<T>
是任意記憶體塊的抽象,因此 Span<T>
具有引數的型別和方法的方法將 Span<T>
在任何物件上操作, Span<T>
而不考慮它所封裝的記憶體型別。
Span<T>
包含方法的兩個過載 Slice ,該方法構成從指定索引處開始的當前範圍的切片。 這樣一來,就可以將中的資料 Span<T>
作為一組邏輯塊進行處理,資料處理管道的部分可以按需處理這些資料塊,並對效能的影響最小。 例如,由於新式伺服器協議通常基於文字,因此字串和子字串的操作非常重要。
可以使用或刪除此分配和複製操作 Span<T>
ReadOnlySpan ,如下面的示例所示:
using System;
class Program
{
static void Main()
{
string contentLength = "Content-Length: 132";
var length = GetContentLength(contentLength.ToCharArray());
Console.WriteLine($"Content length: {length}");
}
private static int GetContentLength(ReadOnlySpan<char> span)
{
var slice = span.Slice(16);
return int.Parse(slice);
}
}
// Output:
// Content length: 132
結語
由於時間關係,本文僅對部分內容進行了簡單整理,尚不足以對C#核心技術進行總結,而最適合深度瞭解C#核心技術的方式,除了通過官方學習網站來了解,可能就是獲得一本深度介紹C#核心技術的書籍,跟著作者的節奏來接觸相關知識體系,瞭解相關程式碼,並手把手的練上一練。
而雖然市場上目前介紹C#相關技術書籍比較多,我比較推薦機械工業出版社華章IT出版的這本《C#8核心技術指南》。作者的介紹也提到,這本書將回答你在C#8.0或.NET CORE學習過程中遇到的各種問題,該書圍繞概念和用例進行組織,不但為中高階程式設計師提供了簡明的C#和.NET知識體系,還進行了一系列深度探索。確實如此,我也從中獲得了許多收穫,解決了許多技術問題。
雖然目前最新的C#已經重新整理到10.0預覽版,但翻譯書的出版速度可能並沒有那麼快,即使是C#9.0,也最快要到明年出版,所以這本《C#8核心技術指南》算是市場上介紹C#8最成熟、最系統的的書籍,不管貴司用的是哪種框架,這本書都一定是非常合適的選擇。