來源:https://blog.guoqianfan.com/2018/11/18/thinking-in-int-TryParse/
問題出現
這天在寫一個頁面,想謹慎些就用了int.TryParse
,結果出問題了。
代碼如下:
int id = 1000;
//Request.QueryString["id"] = null
int.TryParse( Request.QueryString["id"], out id );
//使用 id 進行其他操作...
因為Request.QueryString["id"] = null
,所以我的預期是id=1000
。可是我錯了,實際結果是id=0。測試多次都是這樣。我感覺要出事了。
事實上我對TryParse一直存在這么個認知(以上面代碼舉例):
- 如果轉換成功,id=轉換后的值;
- 如果轉換失敗,不進行任何操作,id仍然是1000。
可是現在我知道我錯了,更嚴重的是我按照這樣的思維寫了不少代碼。。。還好我確保輸入正確使其都能轉化成功,至今沒出什么幺蛾子。出幺蛾子的話我早就滾蛋了吧。
不過現在不是考慮這些的時候,工作要緊,就趕緊改了代碼,先把新功能上線了再說...
問題分析
幾天后,有空了,就開始研究這個問題,總結如下:
TryParse
轉換失敗時,out參數
返回的是什么?
網上搜了下,在stackoverflow上看到了這么一段話(谷歌翻譯):
你是對的,如果失敗,TryParse使用0。(MSDN非常清楚地說明了這一點)但你可以檢查paseSuccess並返回你的默認值,如果這是你想要的。
現在發現當時看的是VB.NET...還好此時此刻這貨特性和C#是一樣的...不然又坑了...
既然提到了MSDN,那就去看看。果然,MSDN上在result
處寫着這么一段話:
result
Int32
當此方法返回時,如果轉換成功,則包含與s
中所包含的數字等效的 32 位無符號整數值;如果轉換失敗,則包含零。 如果s
參數為null
或為 Empty、格式不正確,或者表示小於 MinValue 或大於 MaxValue 的數,則轉換失敗。 此參數未經初始化即進行傳遞;最初在result
中提供的任何值都會被覆蓋。
有這么幾處重點:
- 當此方法返回時,如果轉換成功,則包含與
s
中所包含的數字等效的 32 位無符號整數值;如果轉換失敗,則包含零。 - 此參數未經初始化即進行傳遞;最初在
result
中提供的任何值都會被覆蓋。
”out參數“、“未經初始化即進行傳遞”,看到這些,我突然想到了out
參數的特性:“out
參數好像是不需要初始化的“。如果傳入時不需要初始化,那么在TryParse方法內部,當轉換成功時可以賦值(轉換后的值);當轉換失敗時,也必須賦值,要賦值就必定是默認值。
到此我的疑惑已經解開了。搞了大半天,竟然是out關鍵字
的性質。恍然大悟的同時,又感覺到自己的C#基礎的薄弱。。。
總結
TryParse
使用時,傳入的out
參數的原始值會被覆蓋掉,具體如下:
- 如果轉換成功,使用轉換成功后的值覆蓋
- 如果轉換失敗,使用該類型的默認值覆蓋
其他
轉換失敗時不使用默認值覆蓋原始值的2種方法
既然已經了解了本質,當然也不能忘了咱們的初衷,那就是TryParse轉換失敗時,怎么不使用默認值覆蓋我們設定的原始值?
下面分享一下在stackoverflow上看到的2種方法
//方法1、使用out參數的性質
int i = int.TryParse(s, out i) ? i : 42;
//方法2、擴展方法
public class Extensions
{
public static int? TryParse(string this Source)
{
if(int.tryparse ....
}
}
//使用
v = "234".TryParse() ?? 0
out
關鍵字和ref
關鍵字的區別
說到out
關鍵字,就不得不提ref
關鍵字,他們之間的區別是什么呢?
額,這個稍后我會再寫一篇博文的,到時候此處會貼上鏈接,敬請期待...