---
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>