生活随笔
收集整理的這篇文章主要介紹了
小心VB.NET中的除运算符/和/
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
小心VB.NET中的除運算符"/"和"/"
????? VB.NET中除運算符有兩種,普通除"/"和整數除"/",如果我們寫程序時不注意兩者的區別,很容易造成潛在的錯誤,這種錯誤很隱蔽,不容易被發現。而且VB.NET中類型轉換和C#差別很大,應該引起我們足夠的重視,這些看似微不足道的細節卻直接關系都我們代碼的健壯性。
??????1.問題的引出
??????下面是開發中遇到問題代碼的簡化部分,輸入大部分數據都沒問題,但當輸入數字為18時會拋出異常“System.ArgumentException: 偏移量和長度超出數組的界限,于從索引到源集合結尾處的元素數量。在 System.Collections.ArrayList.GetRange(Int32 index, Int32 count)”。是什么原因使ArrayList集合越界呢?這和VB.NET中的除運算符有什么關系呢?當我們理解了VB.NET中兩種除的區別以及類型轉換(Double—>Integer)的實質后,問題的答案也就不言自明了。
引出問題的代碼
????Sub?Main()
????????Console.WriteLine("請輸入一個整數:")
????????F1(Console.ReadLine())
????????Console.ReadLine()
????End?Sub
????Public?Sub?F1(ByVal?times?As?Integer)
????????Dim?list?As?ArrayList?=?New?ArrayList()
????????'填充數據
????????For?i?As?Integer?=?0?To?29
????????????list.Add(i)
????????Next
????????'把集合list中元素分成times份進行處理
????????Dim?oneTimeNum?As?Integer?=?list.Count?/?times
????????For?i?As?Integer?=?0?To?times?-?1
????????????Dim?length?As?Integer?=?oneTimeNum
????????????If?i?=?times?-?1?Then
????????????????'最后一次循環取集合中所有剩余數據
????????????????length?=?list.Count?-?oneTimeNum?*?i
????????????End?If
????????????'實際中這里是啟動線程處理,這里簡化只是來說明問題
????????????F2(list.GetRange(oneTimeNum?*?i,?length))
????????Next
????End?Sub
????Private?Sub?F2(ByVal?al?As?ArrayList)
????????'對ArrayList集合al進行處理
????End?Sub
??????2.普通除"/"和整數除"/"
????? 1)普通除:expression1 / expression2
????? 結果是 expression1 除以 expression2 的完整的商,包括任何余數。執行除法之前,任何整數數值表達式(除數和被除數)都會被擴展為 Double。如果將結果賦給整數數據類型,Visual Basic 會試圖將結果從 Double 轉換成這種類型。
????? 舉例說明:30 / 18 = 1.6666666666666667,執行除法前被除數30和除數18都擴展為Double類型,結果也為Double類型。
????? 2)整數除:expression1?/ expression2
????? 結果是 expression1 除以 expression2 的整數商,它丟棄了所有余數,只保留整數部分(稱為截斷)。結果數據類型是數值類型,對應于 expression1 和 expression2 的數據類型。值得注意的一點,如果除數或被除數為浮點數,在執行除法前,編譯器會采用“四舍六入五成雙”的規則將其轉換成Long類型,再執行除法。
??????舉例說明:30 / 18 = 1,只保留結果的整數部分。
????? 3.VB.NET中的類型轉換(Double—>Integer)
????? 根據第二部分對普通除的解釋,當CLR執行Dim oneTimeNum As Integer =?30 / 18時,首先將被除數30和除數18都擴展為Double類型,進行除運算得到Double類型的結果1.6666666666666667,因為要將Double類型數據賦值給Integer類型變量,此時要執行強制類型轉換,得到最終結果oneTimeNum = 2(可能很多人和我一樣會奇怪結果為什么不是1)。我們從IL代碼中查看VB.NET中從Double—>Integer類型轉換的實質。
函數F1對應的IL代碼
.method?public?static?void??F1(int32?times)?cil?managed
{
??//?代碼大小???????123?(0x7b)
??.maxstack??3
??.locals?init?([0]?class?[mscorlib]System.Collections.ArrayList?list,
???????????[1]?int32?oneTimeNum,
???????????[2]?int32?i,
???????????[3]?int32?V_3,
???????????[4]?int32?length,
???????????[5]?int32?VB$t_i4$L0,
???????????[6]?int32?VB$CG$t_i4$S0,
???????????[7]?bool?VB$CG$t_bool$S0)
??IL_0000:??nop
??IL_0001:??newobj?????instance?void?[mscorlib]System.Collections.ArrayList::.ctor()
??IL_0006:??stloc.0
??IL_0007:??ldc.i4.0
??IL_0008:??stloc.2
??IL_0009:??ldloc.0
??IL_000a:??ldloc.2
??IL_000b:??box????????[mscorlib]System.Int32
??IL_0010:??callvirt???instance?int32?[mscorlib]System.Collections.ArrayList::Add(object)
??IL_0015:??pop
??IL_0016:??nop
??IL_0017:??ldloc.2
??IL_0018:??ldc.i4.1
??IL_0019:??add.ovf
??IL_001a:??stloc.2
??IL_001b:??ldloc.2
??IL_001c:??ldc.i4.s???29
??IL_001e:??stloc.s????VB$CG$t_i4$S0
??IL_0020:??ldloc.s????VB$CG$t_i4$S0
??IL_0022:??ble.s??????IL_0009
??IL_0024:??ldloc.0
??IL_0025:??callvirt???instance?int32?[mscorlib]System.Collections.ArrayList::get_Count()
??IL_002a:??conv.r8
??IL_002b:??ldarg.0
??IL_002c:??conv.r8
??IL_002d:??div
??IL_002e:??call???????float64?[mscorlib]System.Math::Round(float64)?//重點看這句
??IL_0033:??conv.ovf.i4
??IL_0034:??stloc.1
??IL_0035:??ldc.i4.0
??IL_0036:??ldarg.0
??IL_0037:??ldc.i4.1
??IL_0038:??sub.ovf
??IL_0039:??stloc.s????VB$t_i4$L0
??IL_003b:??stloc.3
??IL_003c:??br.s???????IL_0070
??IL_003e:??ldloc.1
??IL_003f:??stloc.s????length
??IL_0041:??ldloc.3
??IL_0042:??ldarg.0
??IL_0043:??ldc.i4.1
??IL_0044:??sub.ovf
??IL_0045:??ceq
??IL_0047:??stloc.s????VB$CG$t_bool$S0
??IL_0049:??ldloc.s????VB$CG$t_bool$S0
??IL_004b:??brfalse.s??IL_0059
??IL_004d:??ldloc.0
??IL_004e:??callvirt???instance?int32?[mscorlib]System.Collections.ArrayList::get_Count()
??IL_0053:??ldloc.1
??IL_0054:??ldloc.3
??IL_0055:??mul.ovf
??IL_0056:??sub.ovf
??IL_0057:??stloc.s????length
??IL_0059:??nop
??IL_005a:??ldloc.0
??IL_005b:??ldloc.1
??IL_005c:??ldloc.3
??IL_005d:??mul.ovf
??IL_005e:??ldloc.s????length
??IL_0060:??callvirt???instance?class?[mscorlib]System.Collections.ArrayList?[mscorlib]System.Collections.ArrayList::GetRange(int32,
??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????int32)
??IL_0065:??call???????void?VBTest.Module1::F2(class?[mscorlib]System.Collections.ArrayList)
??IL_006a:??nop
??IL_006b:??nop
??IL_006c:??ldloc.3
??IL_006d:??ldc.i4.1
??IL_006e:??add.ovf
??IL_006f:??stloc.3
??IL_0070:??ldloc.3
??IL_0071:??ldloc.s????VB$t_i4$L0
??IL_0073:??stloc.s????VB$CG$t_i4$S0
??IL_0075:??ldloc.s????VB$CG$t_i4$S0
??IL_0077:??ble.s??????IL_003e
??IL_0079:??nop
??IL_007a:??ret
}?//?end?of?method?Module1::F1
??????從IL代碼可以看出,VB.NET中執行類型轉換實際上是調用的函數[mscorlib]System.Math::Round(float64),MSDN中對這個函數的解釋:將雙精度浮點值舍入為最接近的整數,如果參數為兩個整數的中值,這兩個整數一個為偶數,另一個為奇數,則返回偶數(也就是我們常說的“四舍六入五成雙”)。
??????現在,可以很好的解釋文章開始提出的問題了:由于輸入18時,oneTimeNum的值為2,當循環到第16次時i = 15,此時執行list.GetRange(oneTimeNum * i, length)即list.GetRange(30,2),已經超出了list的長度范圍,所以會拋出異常。
??????4.C#和VB.NET的區別
??????1)C#中的除運算"/"符相當于VB.NET的整數除"/"運算符;
????? 2)C#中從Double—>Integer類型轉換必須要采用顯示方式,且轉換規則為直接舍棄小數位。
????? 總結這次出現問題的根源是用C#語法去推斷VB.NET語法,因為接觸C#較早,而C#和VB.NET語法又大同小異,忽略了對VB.NET基本語法的學習,以后應多注意兩種語言的差別,盡量減少類似的錯誤。還有一點需要注意,遇到問題的時候多查MSDN,似乎現在都習慣從網上尋求答案,但網上關于 VB.NET除運算符的內容并不多,找了半天,才發現MSDN上寫的很詳細,我想查找資料的順序應該是:MSDN—>CNBlogs找找看— >Google/Baidu。
Tag標簽: C#,VB,運算符,類型轉換
原文:http://www.cnblogs.com/freshman0216/archive/2008/08/27/1276991.html
與50位技術專家面對面20年技術見證,附贈技術全景圖
總結
以上是生活随笔為你收集整理的小心VB.NET中的除运算符/和/的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。