跳至頁尾內容
Iron Academy Logo
C# 和 .NET 的新功能

在 10 分鐘或更短時間內 C# 10 和 .NET 6 中的常數插值

Tim Corey
6m 14s

隨著每個新版本的推出,C# 的強大性和優雅性不斷演進,為開發者提供更清晰和更高效的編寫程式的方式。 C# 10 中的一項新增功能是常數內插字串——這是一個允許開發者在常數中使用字串插值的功能。

在此功能推出之前,如果您嘗試使用插值來建立常數字串(例如,"${companyName} Products"),編譯器會拋出錯誤。 您只能將純字串文字分配給const 值,這常常導致在構建常數消息或屬性字串時出現重複或笨拙的程式碼。

現在,從 C# 10 和 .NET 6 開始,您可以在編譯時直接使用插值字串來組合常數。這項改進不僅使您的程式碼更清晰,而且保持高效,因為所有值在程式運行之前都經過評估。

為了更清晰地了解這如何運作,Tim Corey 在他的一段影片"Constant Interpolation in C# 10 and .NET 6 In 10 Minutes or Less"中逐步介紹了這一概念。Tim 以他一貫簡潔而實用的教學風格解釋了此新功能的作用、與傳統字串串接的不同之處及其特別有用的情境——特別是在屬性中。

那麼,讓我們來了解 Tim 的解釋,看看 C# 中的常數插值字串如何運作,以及為什麼它們是開發者的有用補充。

介紹

在這段影片中,Tim 解釋了如何在常數表達式中使用插值字串(使用熟悉的美元符號($)語法),這在以前是不可能的。 這一小變化使常數字串的構建更加簡單、清晰和容易維護。

探索 .NET 6 中的常數

Tim 打開了一個 .NET 6 主控台應用程式並移除樣板程式碼,專注於常數定義。

他從最簡單的常數字串聲明開始:

const string companyName = "Acme";
const string companyName = "Acme";

這是一個簡單的字串文字,分配給一個 const 字串。 諸如這樣的常數是在編譯時被評估,這意味著它們的值是固定的,並嵌入到編譯後的程式中。

但 Tim 很快指向關鍵問題:如果我們想將常數字串合併在一起,或直接在其他字串中嵌入值該怎麼辦?

在 C# 9 及更早版本中,您不能這樣做:

const string productName = $"{companyName} Anvils"; // Not allowed before C# 10
const string productName = $"{companyName} Anvils"; // Not allowed before C# 10

由於常數表達式不支持字串插值,這行程式碼會在編譯時報錯。

C# 10 中的常數插值字串

正如 Tim 所示,在 C# 10 中,編譯器現在支持常數內插字串,只要所有內插表達式本身也是常數。

因此,以下範例現在能完美運作:

const string productName = $"{companyName} Anvils";
const string productName = $"{companyName} Anvils";

這是一個常數內插字串,這意味着編譯器在編譯時而非運行時評估內插字串。當程式運行時,沒有額外的字串串接或字串格式化發生——編譯器生成了一個單一的常數字串文字,例如 "Acme Anvils"。

Tim 解釋說,如果我們將 companyName 的值從 "Acme" 改為 "ABC",編譯器會自動為 productName 生成 "ABC Anvils"。 這是編譯時字串構建,而非運行時插值。

這項改進使合併常數字串變得更容易,無需依賴 + 串接或手動重複值。

巢狀常數插值

Tim 更進一步,提出另一常數定義:

const string productDescription = $"{productName} are the best way to crush unsuspecting roadrunners.";
const string productDescription = $"{productName} are the best way to crush unsuspecting roadrunners.";

這是巢狀插值的範例,其中一個常數插值字串(productName)用在另一個中。

編譯器將所有這些視為常數表達式,並在編譯時生成單一不可變的字串表示。

當 Tim 運行程式時,輸出顯示:

Acme Anvils are the best way to crush unsuspecting roadrunners.
Acme Anvils are the best way to crush unsuspecting roadrunners.

這證實了常數插值在多個常數之間無縫運作。

為什麼常數很重要

此時,Tim 暫時解釋為什麼常數——現在包括常數內插字串——是有益的。

他指出常數在記憶體上非常高效,因為它們的值直接儲存在編譯的程式碼中,而不是作為記憶體中的單獨實例。

相比之下,以前開發者需要類似的東西時,通常使用 readonly 字段:

readonly string companyName = "Acme";
readonly string companyName = "Acme";

但 Tim 注意到 readonly 字段與 const 不同——它們是在運行時評估的,這會消耗更多記憶體並阻止編譯時優化。

有了常數內插字串,我們現在可以編寫富表達性且易於重用的格式化字串,同時仍然保持編譯時常數,不僅提高了清晰度,還提升了性能。

實際例子——在屬性中使用常數

接著,Tim 引入了一個現實的情景,該新功能在其中大放異彩——屬性。

他在 Main() 中定義了一個簡單的本地方法:

void SayHi() { }
void SayHi() { }

然後他嘗試用一個字串消息(引用一個變數)來應用 [Obsolete] 屬性:

string myCompany = "Tim's Company";
[Obsolete($"This is no longer used for {myCompany}")]
string myCompany = "Tim's Company";
[Obsolete($"This is no longer used for {myCompany}")]

這失敗了,因為屬性只能接受常數表達式作為參數。 編譯器生成錯誤,因為 myCompany 是一個變數,而不是常數。

Tim 解釋說,屬性的消息必須是編譯時常數——不能依賴運行時值或實例變數。

然而,感謝 C# 10 中的常數內插字串,我們現在可以安全地做到這一點:

const string productName = $"{companyName} Anvils";
[Obsolete($"This is no longer used for {productName}")]
const string productName = $"{companyName} Anvils";
[Obsolete($"This is no longer used for {productName}")]

在這裡,編譯器識別出 companyName 和 productName 都是常數,因此整個插值字串是常數表達式。

編譯器在編譯時生成格式化字串,使其在屬性中有效。

這個例子完美地突顯了為什麼常數插值不僅僅是語法糖——它啟用了新的情景,如直接在屬性或元資料中使用格式化編譯時字串。

背後的原理——編譯器如何處理它

Tim 在影片中沒有深入到低層次的編譯器內部,但這一概念與 C# 10 中插值字串處理的工作方式密切相關。

通常,當編譯器遇到插值字串時,它會建立類似格式字串操作的程式碼,在幕後生成像 AppendLiteral() 和 AppendFormatted() 這樣的調用。

但在處理常數內插字串時,編譯器在編譯時評估一切——生成的 IL 程式碼中不會產生插值字串處理器或方法調用。

這意味著,結果值的行為與任何字串文字完全相同,但您仍然可以使用其他常數中的嵌入表達式來組合它。

這在表達性和效率之間取得了優雅的平衡——編譯器靜態處理字串構建,確保零運行時成本。

何時使用常數插值字串

Tim 承認不是每個人每天都會使用此功能。 很少定義常數或編寫屬性的開發者可能不會馬上受益。

然而,對於那些建立許多編譯時定義、常數消息或屬性元資料的人來說,此功能簡化了程式碼並防止字串串接混亂。

它還更安全——因為常數是不可變的,並由編譯器檢查,您消除了由動態串接字串或管理不當的變數造成的錯誤。

這使您的程式碼更加強壯、可讀性更高且更容易維護。

結論

在 Tim 結束他的影片時,他邀請開發者思考他們是否會在專案中使用常數插值字串。 有些人可能會發現它們對於更乾淨的編譯時格式化字串至關重要,而其他人可能只將其視為一項小便利。

無論哪種方式,Tim 的展示清楚地顯示了如何實現並在何處有效應用此功能。

總結:

  • 常數內插字串允許在常數中使用插值表達式。

  • 它們在編譯時進行評估,產生效率高的字串文字。

  • 它們用更簡潔的語法取代重複的字串串接。

  • 它們在屬性、基於常數的配寘和元資料消息中特別有用。

通過將可讀性與編譯時的安全性相結合,C# 10 的常數插值是朝著更具表達性和效率的 C# 程式設計邁出的又一步——正如 Tim Corey 的例子清晰地展示的那樣。

Hero Worlddot related to 在 10 分鐘或更短時間內 C# 10 和 .NET 6 中的常數插值
Hero Affiliate related to 在 10 分鐘或更短時間內 C# 10 和 .NET 6 中的常數插值

分享您所愛以賺取更多報酬

您是否為使用 .NET、C#、Java、Python 或 Node.js 的開發者建立內容?將您的專業知識轉化為額外收入!

Iron 支援團隊

我們線上24小時,每週5天。
聊天
電子郵件
給我打電話