--- title: Convert.ToInt32 / int32.Parse / int32.TryParse 該怎麼用? tags: ASP.NET,C# --- Convert.ToInt32 / int32.Parse / int32.TryParse 該怎麼用? === ###### tags: `ASP.NET` `C#` ### :memo: 資料來源放哪裡? > 唉...,真是麻煩的規則,各國幣別小數位都不相同,要怎麼設定這些資料阿? > 這個不難阿,不就把**規則寫好存放著**就好了,至於放哪... 你想怎麼做? > 我是想寫**類似Util的工具,包成一包帶著走**,只是這樣到底搞不好維護呢... > 不如... <font color="red">**放在資料庫當作做config檔設定**</font>如何?如此一來就不用進程式裡調整維護 > 好像是這樣,不用去看程式碼...即使接手也很好維護...,決定了!就用這種做法了! 上述的小故事經常發生在工程師coding過程,像是這種**固定且有規範**的東西 建議是集中放在某處管理,至於要放在哪? >1. 放在**DB端設定畫面**供使用者直接修改? >2. **存放在config檔**讓資訊部門的人修改呢? >3. **放在程式碼**裡一直頻繁調整? 其實每種方法都可達成目的,只是<font color="red">**後續的維護成本看誰比較低、比較方便**</font>而已 :arrow_down: 接下來將針對資料轉換過程,上述部分就請大家好好思考下,最後再跟大家討論各利弊問題 --- #### Ⅰ. Convert.ToInt32 V.S. Int32.Parse 兩者都是針對非Int型別做轉換的動作,以下為測試案例及結果:arrow_down: - 測試代碼 ```C# public void numberParse (){ var numberStrValue = "88"; string numberStrNull = null; Console.WriteLine(Convert.ToInt32(numberStrValue)); Console.WriteLine(Convert.ToInt32(numberStrNull)); Console.WriteLine(Int32.Parse(numberStrValue)); Console.WriteLine(Int32.Parse(numberStrNull)); } ``` - 測試結果 ![](https://i.imgur.com/ae0dPn7.png) 上述兩者發現,當參數型別為null值時,Convert與Int轉換工具各有不同的產出 ```graphviz digraph{ pp1; pp2; a; b; a1; b2; pp1a; pp1b; pp2a1; pp2b2; subgraph cluster_a{ pp1[label="88"] a[label="Convert.ToInt32"]; b[label="Int.Parse"] pp1a[label="88"] pp1b[label="88"] pp1 -> {a, b}; a -> {pp1a} b -> {pp1b} color="white" } subgraph cluster_b{ pp2[label="null"] a1[label="Convert.ToInt32"] b2[label="Int.Parse"] pp2a1[label="0"] pp2b2[label="ArgumentNullException"; color="red" style="filled"] pp2 -> {a1, b2} a1 -> {pp2a1} b2 -> {pp2b2} color="white" } } ``` 返回頭查詢了下兩邊各自的原始碼,發現了一些事情 - Convert.ToInt32 原始碼 ```C# public static int ToInt32(string value) { if (value == null) { return 0; } return int.Parse(value, CultureInfo.CurrentCulture); } ``` - Int32.Parse 原始碼 ```C# public static int Parse(string s) { return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo); } ``` - Number.ParseInt32 原始碼 ```C# internal unsafe static Int32 ParseInt32(String s, NumberStyles style, NumberFormatInfo info) { Byte * numberBufferBytes = stackalloc Byte[NumberBuffer.NumberBufferBytes]; NumberBuffer number = new NumberBuffer(numberBufferBytes); Int32 i = 0; StringToNumber(s, style, ref number, info, false); if ((style & NumberStyles.AllowHexSpecifier) != 0) { if (!HexNumberToInt32(ref number, ref i)) { throw new OverflowException(Environment.GetResourceString("Overflow_Int32")); } } else { if (!NumberToInt32(ref number, ref i)) { throw new OverflowException(Environment.GetResourceString("Overflow_Int32")); } } return i; } ``` Convert.ToInt32 和 Int.Parse 差別只有在參數為null時 **前者會判斷null值,而後者是產生Exception,其兩者基本上做的事情<font color="red">並無差多少</font>** :::info :bulb: 基本上兩者都使用同個function產出,差別在<font color="red">**是否判斷null值**</font> ::: --- #### Ⅱ. Int32.Parse V.S. Int32.TryParse 以下為測試案例代碼的建構 :arrow_down: - 測試代碼 ```C# public void tryParseTest(){ var numberStrFail = "8923ava"; Console.WriteLine(Int32.TryParse(numberStrFail, out var result)); Console.WriteLine(result); Console.WriteLine(result.GetType()); Console.WriteLine(numberStrFail.GetType()); Console.WriteLine(); var numberStrSucces = "8999"; Console.WriteLine(Int32.TryParse(numberStrSucces, out var resultOut)); Console.WriteLine(resultOut); Console.WriteLine(resultOut.GetType()); Console.WriteLine(numberStrSucces.GetType()); } ``` - 測試結果 ![](https://i.imgur.com/I1mNlLP.png) 從上述結果圖可以看的出來,當String型別資料不可轉換成Int型別時 TryParse function會回傳False,並且會<font color="red">**output一個參數型別為Int32,值為0**</font> 我們在近一步回頭去看TryParse的程式碼 ```C# internal unsafe static Boolean TryParseInt32(String s, NumberStyles style, NumberFormatInfo info, out Int32 result) { Byte * numberBufferBytes = stackalloc Byte[NumberBuffer.NumberBufferBytes]; NumberBuffer number = new NumberBuffer(numberBufferBytes); result = 0; if (!TryStringToNumber(s, style, ref number, info, false)) { return false; } if ((style & NumberStyles.AllowHexSpecifier) != 0) { if (!HexNumberToInt32(ref number, ref result)) { return false; } } else { if (!NumberToInt32(ref number, ref result)) { return false; } } return true; } ``` 將其與Parse32比較後可以發現,差別分別為 - StringToNumber / TryStringToNumber - HexNumerToInt32 - NumberToInt32 以上function作動方式與原Parse32 function無差別,只是**後續的function**回傳資料有不一樣 :::danger - **Parse回傳Exception** - **TryParse回傳Boolean資料** ::: --- ### :writing_hand: 結論 現在要來說說個人對於資料存放在哪比較妥當,從開頭的故事可以分成三個面向 - **DataBase** : 開表格存放,並聯動前端畫面供使用者自行調整 - **Config檔** : 設定存放,透過更改後並再載入系統中 - **Constant陣列物件** : HardCode在程式碼裡並透過前端呼叫取得 ||優點|缺點| |--|--|--| |DataBase|只需要**更動DB資料即可改變畫面**<br>使用者可自行設定|<font color="red">**開發時測試相較長**</font><br>但若熟悉可以壓縮開發時間| |Config|**統一管理在properties**檔案內<br>不必重新閱讀程式碼即可快速維護|當properties檔一旦變多不好管理<br>且<font color="red">**變更後須重新啟動伺服器**</font>| Constant Array|開發速度最快最方便<br>**開發時期更改方便**|<font color="red">**日後維護需重新閱讀程式碼**</font><br>後續須有人力了解當時開發方式| 若**時程真得很緊湊**,個人傾向第二種 <font color="red">**遠大於**</font> 第三種 **時間充裕**且**DB有類似的資料儲存區域**,第一種的靈活性 <font color="red">**遠大於**</font> 其他兩種 第三種方案只有可能發生在**接小型案子**且**時程只有1-2個禮拜開發**,又或者想要多要維護金額 不然沒有工程師想要害自己,結案後還要回來一直看程式碼 :joy::joy::joy: --- ### :computer: 連結 <div class="link-Table"> | 參考網站 | 連結 | |:------------------------------------------------------------------ |:----------------------------------------------------------------------------:| | 字串轉數字 | [:link:][字串轉數字] | | What's the main difference between int.Parse() and Convert.ToInt32 | [:link:][What's the main difference between int.Parse() and Convert.ToInt32] | | ParseInt32原始碼 | [:link:][ParseInt32原始碼] | | TryParseInt32原始碼 | [:link:][TryParseInt32原始碼] | [字串轉數字]:https://dotblogs.com.tw/lapland/2015/12/10/161527 [What's the main difference between int.Parse() and Convert.ToInt32]: https://stackoverflow.com/questions/199470/whats-the-main-difference-between-int-parse-and-convert-toint32 [ParseInt32原始碼]:https://referencesource.microsoft.com/#mscorlib/system/number.cs,fc92e899c667fab0 [TryParseInt32原始碼]:https://referencesource.microsoft.com/#mscorlib/system/number.cs,958cb8bc00d00a94 </div> <style> div.link-Table > table th:nth-of-type(1) { width: 90vw; } div.link-Table > table th:nth-of-type(2) { width: 10vw; } </style>