C# Interpolated Strings 字串插值
7 | 16,795 |
TypeScript 有個好東西,Template String,輸出內嵌動態資料 HTML 時非常好用,例如:
排版顯示純文字
var userName: string = "Jeffrey";
var iconUrl: string = "/imgs/runner.gif";
var html = `
<div>
Hello, ${userName}! <img src="${iconUrl}" />
</div>`;
alert(html);
場景移到 C#,字串內含換行符號靠 @"…." (String Literal,字串常值)可輕鬆擺平,是 .NET 1.1 時代就有的老東西。TypeScript 在字串裡用 ${variable_name}
直接穿插變數的做法稱為 String Interpolation,C# 傳統上靠 string.Format("<div>Hello, {0}</div>", userName)
實現(術語為 Composite Format,複合格式)。C# 6.0 起新加入 Interpolated Strings(字串插值)特性,不需再用 string.Format() 就可直接混搭文字與變數。
使用 Interpolated String 時只需在雙引號前加上 $ 符號,即可在字串中大大方方以大括號夾入變數,例如:$"Hi, {userName}.",同時還可比照 string.Format(),以 :n0、:yyyy-MM-dd 指定格式,十分方便。不囉嗦,直接看範例:
排版顯示純文字
class Program
{
static void Main(string[] args)
{
//插入變數,比照string.Format可加上:n0,:yyyy-MM-dd等格式規範
var userName = "Jeffrey";
var score = 32767;
var result = $"{userName}'s score is {score:n0}. {DateTime.Today:yyyy-MM-dd}";
Console.WriteLine(result);
//指定固定寬度
var items = new string[] { "Notebook", "Phone", "PC" };
foreach (var item in items)
{
Console.WriteLine($"{item, 12} checked.");
}
//加入邏輯運算,與@""混合使用以支援換行,用{{、}}代表{、}
Console.WriteLine($@"
{{ {score} + 1 = {score + 1} }}
{score} is {(score % 2 == 0 ? "even":"odd")}
");
Console.Read();
}
}
執行結果:
Jeffrey's score is 32,767. 2016-11-22 Notebook checked. Phone checked. PC checked. { 32767 + 1 = 32768 } 32767 is odd
注意:Interpolated String 屬 C# 6.0 新增規格,Visual Studio 2015 起才支援(參考),如果你的專案開發環境仍停留在 Visual Studio 2013,看在可以少打好多字的份上,考慮升級吧!:P
Comments
# by PcLEE
請問這個方式的記憶體使用是如 StringBuilder 先畫出一個稍微大一點的記憶體空間 還是和string += 一樣,每次的建立都是重新指派記憶體空間
# by Jeffrey
to PcLEE, Interpolated Strings 編譯後等同 String.Format("{0} {1}", arg0, arg1),而 String.Format 內部則使用StringBuilder 實作字串組裝。
# by PcLEE
謝謝您的回覆
# by Vinix
我在Visual Studio 2019 (16.4.2)下,在專案內容及web.config中設定Target Framework為4.7.2,但是當我在WebForm Project內的網頁(.aspx)使用 interpolated strings ,則會出現錯誤:Error CS8026 Feature 'interpolated strings' is not available in C# 5. Please use language version 6 or greater. 詭異的是當我在.cs內使用,則不會出現此錯誤。請問這有解嗎?
# by Jeffrey
to Vinix,我倒沒遇過。會是 VS C# 版本設定問題嗎?https://blog.darkthread.net/blog/set-vs-language-version/
# by ChrisTorng
我在 .NET 6 實測發現「Interpolated Strings 編譯後等同 String.Format("{0} {1}", arg0, arg1)」是不正確的。https://devblogs.microsoft.com/dotnet/string-interpolation-in-c-10-and-net-6/ 中有一些說明。我推測 String.Format 只是單純函式呼叫就都照叫,但 $"" 是 compiler 功能,可以實現很多最佳化,比如 $"{"a"}" 轉譯出來就是 "a",完全沒用 Format 函式。我寫了小專案搭配 dnSpy 測試,發現最佳化的影響蠻大的,而且有些看不懂為什麼: C#: var a = "a"; Console.WriteLine("a 1"); Console.WriteLine("a" + " 2"); Console.WriteLine('a' + " 3"); Console.WriteLine(nameof(a) + " 4"); Console.WriteLine(a + " 5"); Console.WriteLine(String.Format("{0} 6", "a")); Console.WriteLine(String.Format("{0} 7", a)); Console.WriteLine(String.Format("{0} 8", nameof(a))); Console.WriteLine($"a 9"); Console.WriteLine($"{"a"} 10"); Console.WriteLine($"{a} 11"); Console.WriteLine($"{nameof(a)} 12"); Console.WriteLine($"{a}" + $" 13"); Console.WriteLine($"{a}{a}"); Console.WriteLine($"{a}{a}{a}"); Console.WriteLine($"{a}{a}{a}{a}"); Console.WriteLine($"{a}{a}{a}{a}{a}"); Console.WriteLine($"{a} {a}"); Console.WriteLine($"{a} {a} {a}"); Console.WriteLine($"{a}" + $"{a}"); Console.WriteLine($"{a}" + $"{a}" + $"{a}"); Console.WriteLine($"{a}" + $"{a}" + $"{a}" + $"{a}"); Console.WriteLine($"{a}" + $"{a}" + $"{a}" + $"{a}" + $"{a}"); Console.WriteLine($"{a} " + $" {a}"); Console.WriteLine($"{a} " + $" {a} " + $" {a}"); Console.WriteLine($"{a} " + $" {a} " + $" {a} " + $" {a}"); dnSpy: string a = "a"; Console.WriteLine("a 1"); Console.WriteLine("a 2"); Console.WriteLine("a 3"); Console.WriteLine("a 4"); Console.WriteLine(a + " 5"); Console.WriteLine(string.Format("{0} 6", "a")); Console.WriteLine(string.Format("{0} 7", a)); Console.WriteLine(string.Format("{0} 8", "a")); Console.WriteLine("a 9"); Console.WriteLine("a 10"); Console.WriteLine(a + " 11"); Console.WriteLine("a 12"); Console.WriteLine(a + " 13"); Console.WriteLine(a + a); Console.WriteLine(a + a + a); Console.WriteLine(a + a + a + a); DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(0, 5); defaultInterpolatedStringHandler.AppendFormatted(a); defaultInterpolatedStringHandler.AppendFormatted(a); defaultInterpolatedStringHandler.AppendFormatted(a); defaultInterpolatedStringHandler.AppendFormatted(a); defaultInterpolatedStringHandler.AppendFormatted(a); Console.WriteLine(defaultInterpolatedStringHandler.ToStringAndClear()); Console.WriteLine(a + " " + a); defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(2, 3); defaultInterpolatedStringHandler.AppendFormatted(a); defaultInterpolatedStringHandler.AppendLiteral(" "); defaultInterpolatedStringHandler.AppendFormatted(a); defaultInterpolatedStringHandler.AppendLiteral(" "); defaultInterpolatedStringHandler.AppendFormatted(a); Console.WriteLine(defaultInterpolatedStringHandler.ToStringAndClear()); Console.WriteLine(a + a); Console.WriteLine(a + a + a); Console.WriteLine(a + a + a + a); defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(0, 5); defaultInterpolatedStringHandler.AppendFormatted(a); defaultInterpolatedStringHandler.AppendFormatted(a); defaultInterpolatedStringHandler.AppendFormatted(a); defaultInterpolatedStringHandler.AppendFormatted(a); defaultInterpolatedStringHandler.AppendFormatted(a); Console.WriteLine(defaultInterpolatedStringHandler.ToStringAndClear()); Console.WriteLine(a + " " + a); Console.WriteLine(string.Concat(new string[] { a, " ", a, " ", a })); Console.WriteLine(string.Concat(new string[] { a, " ", a, " ", a, " ", a }));
# by Jeffrey
to ChrisTorng, 到 C# 9/.NET 5 都還是用 String.Format() 實現,C# 10 才砍掉重練的,這篇文章有提到新做法的細節:https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-10.0/improved-interpolated-strings?WT.mc_id=DOP-MVP-37580