iT邦幫忙

2023 iThome 鐵人賽

DAY 8
0
自我挑戰組

30天開啟.NET後端工程師的旅程系列 第 8

Day 8 數值格式化 StringBuilder 類型轉換

  • 分享至 

  • xImage
  •  

前言

前面的內容截至目前關於C#基礎的知識大多都講解得差不多了。
這裡做進階的補充。

數值格式化

如果需要呈現格式化數字時,可以使用以下的方法來處理百分比、千分位和自訂數值格式化。

  1. 百分比格式化:

    double percent = 0.5;
    Console.WriteLine($"百分比格式化:{percent:P}");  // 百分比格式化:50.00%
    Console.WriteLine($"百分比格式化(2位小數):{percent:P2}");  // 百分比格式化(2位小數):50.00%
    Console.WriteLine($"百分比格式化(1位小數):{percent:P1}");  // 百分比格式化(1位小數):50.0%
    Console.WriteLine($"百分比格式化(整數):{percent:P0}");  // 百分比格式化(整數):50%
    

https://ithelp.ithome.com.tw/upload/images/20230920/20151470ejCAARRf4L.png

  1. 千分位格式化:

    int num = 1000000;
    Console.WriteLine($"千分位格式化:{num:N}");  // 千分位格式化:1,000,000.00
    Console.WriteLine($"千分位格式化(無小數位):{num:N0}");  // 千分位格式化(無小數位):1,000,000
    Console.WriteLine($"千分位格式化(1位小數):{num:N1}");  // 千分位格式化(1位小數):1,000,000.0
    Console.WriteLine($"千分位格式化(2位小數):{num:N2}");  // 千分位格式化(2位小數):1,000,000.00
    

https://ithelp.ithome.com.tw/upload/images/20230920/20151470VWUFqBCuXH.png

  1. 自訂數值格式化,保留小數點後2位:

    double num1 = 10.1;
    Console.WriteLine($"自訂數值格式化(2位小數):{num1:0.00}");  // 自訂數值格式化(2位小數):10.10
    
    double num2 = 0.1987;
    Console.WriteLine($"自訂數值格式化(2位小數):{num2:0.00}");  // 自訂數值格式化(2位小數):0.20
    Console.WriteLine($"自訂數值格式化(2位小數,不顯示0):{num2:#.00}");  // 自訂數值格式化(2位小數,不顯示0):.20
    

https://ithelp.ithome.com.tw/upload/images/20230920/20151470zaB44f79n4.png


StringBuilder

StringBuilder 是什麼? StringBuilder是在 .NET 中的一個類,用於動態地建立、修改和處理字串。

與 string 不同, StringBuilder 物件是可變的,意思是可以在不創建新字串的情況下對字串進行連接和修改。這個方法在需要頻繁修改文字的情況下特別有用,例如報表生成、文字處理、日誌記錄等。

那關於string不可變跟StringBuilder可變是差異在哪裡,是甚麼意思??

  1. 不可變性: 字串 (string) 在 .NET 中是不可變的,意思就是一旦創建,就不能修改。
    我們每次對 string 執行操作(例如連接、拼接或修改),都會創建一個新的 string 實例,並將修改後的內容複製到新的實例中。這樣會導致了大量的記憶體分配和拷貝操作,也就是說這樣的操作對於大量數據將導致內存和性能開銷,特別是在迴圈中執行這些操作時。

    但反過來如果您的字串是固定的,不需要在運行時進行修改,則 string 是合適的選擇。
    對於簡單的字串操作,例如連接幾個固定字串或執行基本的字串搜索和替換,用 string 就夠了,因為它提供了方便的方法和運算子,並且通常具有良好的性能。

  2. StringBuilder 的可變性: StringBuilder 被設計成可變的,它內部維護一個字符緩衝區,允許在其中添加、插入或移除字符,可以有效地執行連接和修改操作,而不需要創建新的實例。這意味著在迴圈中使用不會產生大量的字串實例,從而減少記憶體使用和提高性能。

如果需要動態修改字串或執行大量的字串連接操作,則 StringBuilder 可以提供更好的性能。
如果字串是固定的且不需要修改,或者操作相對簡單,則 string 可以更容易使用並且足夠應對需求。

為什麼使用 StringBuilder?
如果需要連接或修改大量文字時,使用 string 可能會導致性能問題,如上面不可變性裡面提到的,每次對 string 執行操作時,都會創建一個新的 string 實例。這樣就會影響到性能。

(雖然string 類型的物件最終會被 .NET 中的垃圾回收器(Garbage Collector,簡稱 GC)回收。垃圾回收器的主要作用是追蹤和回收不再被引用的物件,以釋放佔用的內存,從而確保應用程序不會耗盡系統的記憶體。)

而 StringBuilder 則通過在內部維護一個可擴展的字符緩衝區來解決這個問題,從而提供更高的性能。

如何使用 StringBuilder?

  1. 創建 StringBuilder 實例:首先,您需要創建一個 StringBuilder 對象,通常使用 new StringBuilder() 構造函數。
  2. 使用 Append 方法:使用 Append 方法把文字附加到 StringBuilder 的內部緩衝區。這樣可以在不創建新字串的情況下串聯文字。
  3. 使用 ToString 方法:當完成所有的操作後,使用 ToString 方法將 StringBuilder 的內容轉換為最終的 string 。

範例:
以下是個簡單的例子,來看看如何使用 StringBuilder 來連接大量文字:

var sb = new StringBuilder();

for (int i = 0; i < 100000; i++)
{
    sb.Append("文字"); // 將文字附加到 StringBuilder
}

string result = sb.ToString(); // 將 StringBuilder 內容轉換為 string

Console.WriteLine(result.Length); // 顯示文字的長度

https://ithelp.ithome.com.tw/upload/images/20230920/20151470cq5AJ78b4R.png

這樣就可以更有效率地處理大量文字數據,比較不需要擔心性能問題。在需要處理大型報表、生成大量文字的應用程序中,使用 StringBuilder 是一個重要的優化工具。

明確類型轉換(explicit type conversion)的方法。

這些方法允許明確地將一種資料型別轉換為另一種,而不依賴於隱含的型別轉換規則。(ToStringToInt32)

那剛剛上面StringBuilder裡面提到的ToString方法又是甚麼??
我們常常會有機會使用到這個方法,主要適用於把對象轉換成字串表示形式。
ToString方法用於將某個資料類型(通常是數值或物件)轉換為字串。

當我們呼叫這個方法的時候會回傳一個字串,回傳的這個字串描述了這個對象裡面的內容,像是可以把一些基本數據類型(例如 intdoubleDateTime 等)裡面的內容,使用這個方法轉換成字串表示形式。

下面是簡易的示範例子

int num = 22;
string strNum = num .ToString();
Console.WriteLine(strNum ); // Output: "22"

可以看到,strNum 前面是string的類型,表示num加上.ToString()這個方法,會變成字串string的類型才可以被放到string strNum裡面。

換個方式看,當我們程式碼運作的時候,如果這時候滑鼠游標滑到strNum可以看到下面顯示這個(區域變數)string strNum表示有成功轉換成string的類型。
https://ithelp.ithome.com.tw/upload/images/20230920/20151470FjERuGxLx3.png
除了int可以轉換以外,還有其他幾個可以使用ToString轉換的,像是可以自訂日期時間格式

static void Main()
		{
			CustomDate customDate = new CustomDate { Day = 5, Month = 9, Year = 2023 };
			Console.WriteLine(customDate); // Output: "09/05/2023"
		}
		class CustomDate
		{
			public int Day { get; set; }
			public int Month { get; set; }
			public int Year { get; set; }

			public override string ToString()
			{
				return $"{Month:D2}/{Day:D2}/{Year}";
			}
		}

可以看到下圖輸出的格式也是字串的形式呈現。
https://ithelp.ithome.com.tw/upload/images/20230920/20151470mInlEJbyGN.png

上面程式碼創建了一個 CustomDate的class類別,用這個類別覆寫了 ToString的方法,以自訂日期格式呈現出雙位數的月份還有日期形式。

換成自訂集合類別的 ToString

Day 7 的時候有提到關於集合使用的方式,這裡就加上集合跟ToString來練習呈現(如果忘記.Add可以到
Day 7的集合去看)。

static void Main()
		{
			CustomCollection<int> collection = new CustomCollection<int>();
			collection.Add(1);
			collection.Add(2);
			collection.Add(3);
			Console.WriteLine(collection); // Output: "1, 2, 3"
		}
		class CustomCollection<T>
		{
			private List<T> items = new List<T>();

			public void Add(T item)
			{
				items.Add(item);
			}

			public override string ToString()
			{
				return string.Join(", ", items);
			}
		}

https://ithelp.ithome.com.tw/upload/images/20230920/201514707IEIJtfqGN.png

錯誤訊息格式也可以自訂

static void Main()
		{
			CustomError error = new CustomError("This is a custom error.");
			Console.WriteLine(error); // Output: "Custom Error: This is a custom error."
		}
		class CustomError : Exception
		{
			public CustomError(string message) : base(message) { }

			public override string ToString()
			{
				return $"Custom Error: {Message}";
			}
		}

自訂的錯誤類別 CustomError 繼承自 Exception,並覆寫了 ToString 方法,以自訂錯誤訊息的格式。
https://ithelp.ithome.com.tw/upload/images/20230920/20151470NlCgudv7mH.png

在前面Day4 提到使用.Parse的方法
這上面也提到可以用ToString轉換成字串,那還有另一個轉換成整數的方法,這裡補充這個轉換成整數的另外一個方法。

ToInt32:這是一個方法,用於將某種資料型別(通常是字串或其他數值型別)轉換為整數( int )。它需要一個明確的轉換操作,因為不是所有的資料型別都能夠隱含地轉換為整數。
雖然 Convert.ToInt32 和 int.Parse 都是將字串轉換為整數的方法,但它們兩個還是有差異:

  1. 處理 null 或空字串:

    • Convert.ToInt32:當傳遞 null 或空字串給 Convert.ToInt32 時,它會導致 0 的返回值,不會引發異常。
    • int.Parse:之前有提到當傳遞 null 或空字串給 int.Parse 時,它會引發 System.FormatException 異常。
    string nullString = null;
    string emptyString = "";
    
    int result1 = Convert.ToInt32(nullString); // result1 為 0
    int result2 = Convert.ToInt32(emptyString); // result2 為 0
    
    int result3 = int.Parse(nullString); // 會引發 FormatException 異常
    int result4 = int.Parse(emptyString); // 會引發 FormatException 異常
    
  2. 處理無效格式的字串:

    • Convert.ToInt32:當傳遞無效格式的字串給 Convert.ToInt32 時,它會導致 0 的返回值,不會引發異常。
    • int.Parse:當傳遞無效格式的字串給 int.Parse 時,它會引發 System.FormatException 異常。
string invalidString = "abc";

int result1 = Convert.ToInt32(invalidString); // result1 為 0
int result2 = int.Parse(invalidString); // 會引發 FormatException 異常

第8天完成,越寫越覺得自己還有許多需要複習的地方,最初在學習的時候並沒有理解,雖然在大量練習的過程中,知道哪時候可以用甚麼,但透過撰寫的過程才真的有逐漸的理解過去不那麼明白的地方,期許可以保持這樣的學習的動力繼續完成挑戰。


上一篇
Day 7 Array 陣列
下一篇
Day 9 Class 類別
系列文
30天開啟.NET後端工程師的旅程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言