生活随笔
收集整理的這篇文章主要介紹了
小心VB.NET中的除运算符/和/
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
小心VB.NET中的除運(yùn)算符"/"和"/"
????? VB.NET中除運(yùn)算符有兩種,普通除"/"和整數(shù)除"/",如果我們寫程序時(shí)不注意兩者的區(qū)別,很容易造成潛在的錯(cuò)誤,這種錯(cuò)誤很隱蔽,不容易被發(fā)現(xiàn)。而且VB.NET中類型轉(zhuǎn)換和C#差別很大,應(yīng)該引起我們足夠的重視,這些看似微不足道的細(xì)節(jié)卻直接關(guān)系都我們代碼的健壯性。
??????1.問題的引出
??????下面是開發(fā)中遇到問題代碼的簡化部分,輸入大部分?jǐn)?shù)據(jù)都沒問題,但當(dāng)輸入數(shù)字為18時(shí)會拋出異常“System.ArgumentException: 偏移量和長度超出數(shù)組的界限,于從索引到源集合結(jié)尾處的元素?cái)?shù)量。在 System.Collections.ArrayList.GetRange(Int32 index, Int32 count)”。是什么原因使ArrayList集合越界呢?這和VB.NET中的除運(yùn)算符有什么關(guān)系呢?當(dāng)我們理解了VB.NET中兩種除的區(qū)別以及類型轉(zhuǎn)換(Double—>Integer)的實(shí)質(zhì)后,問題的答案也就不言自明了。
引出問題的代碼
????Sub?Main()
????????Console.WriteLine("請輸入一個(gè)整數(shù):")
????????F1(Console.ReadLine())
????????Console.ReadLine()
????End?Sub
????Public?Sub?F1(ByVal?times?As?Integer)
????????Dim?list?As?ArrayList?=?New?ArrayList()
????????'填充數(shù)據(jù)
????????For?i?As?Integer?=?0?To?29
????????????list.Add(i)
????????Next
????????'把集合list中元素分成times份進(jìn)行處理
????????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
????????????????'最后一次循環(huán)取集合中所有剩余數(shù)據(jù)
????????????????length?=?list.Count?-?oneTimeNum?*?i
????????????End?If
????????????'實(shí)際中這里是啟動(dòng)線程處理,這里簡化只是來說明問題
????????????F2(list.GetRange(oneTimeNum?*?i,?length))
????????Next
????End?Sub
????Private?Sub?F2(ByVal?al?As?ArrayList)
????????'對ArrayList集合al進(jìn)行處理
????End?Sub
??????2.普通除"/"和整數(shù)除"/"
????? 1)普通除:expression1 / expression2
????? 結(jié)果是 expression1 除以 expression2 的完整的商,包括任何余數(shù)。執(zhí)行除法之前,任何整數(shù)數(shù)值表達(dá)式(除數(shù)和被除數(shù))都會被擴(kuò)展為 Double。如果將結(jié)果賦給整數(shù)數(shù)據(jù)類型,Visual Basic 會試圖將結(jié)果從 Double 轉(zhuǎn)換成這種類型。
????? 舉例說明:30 / 18 = 1.6666666666666667,執(zhí)行除法前被除數(shù)30和除數(shù)18都擴(kuò)展為Double類型,結(jié)果也為Double類型。
????? 2)整數(shù)除:expression1?/ expression2
????? 結(jié)果是 expression1 除以 expression2 的整數(shù)商,它丟棄了所有余數(shù),只保留整數(shù)部分(稱為截?cái)?#xff09;。結(jié)果數(shù)據(jù)類型是數(shù)值類型,對應(yīng)于 expression1 和 expression2 的數(shù)據(jù)類型。值得注意的一點(diǎn),如果除數(shù)或被除數(shù)為浮點(diǎn)數(shù),在執(zhí)行除法前,編譯器會采用“四舍六入五成雙”的規(guī)則將其轉(zhuǎn)換成Long類型,再執(zhí)行除法。
??????舉例說明:30 / 18 = 1,只保留結(jié)果的整數(shù)部分。
????? 3.VB.NET中的類型轉(zhuǎn)換(Double—>Integer)
????? 根據(jù)第二部分對普通除的解釋,當(dāng)CLR執(zhí)行Dim oneTimeNum As Integer =?30 / 18時(shí),首先將被除數(shù)30和除數(shù)18都擴(kuò)展為Double類型,進(jìn)行除運(yùn)算得到Double類型的結(jié)果1.6666666666666667,因?yàn)橐獙ouble類型數(shù)據(jù)賦值給Integer類型變量,此時(shí)要執(zhí)行強(qiáng)制類型轉(zhuǎn)換,得到最終結(jié)果oneTimeNum = 2(可能很多人和我一樣會奇怪結(jié)果為什么不是1)。我們從IL代碼中查看VB.NET中從Double—>Integer類型轉(zhuǎn)換的實(shí)質(zhì)。
函數(shù)F1對應(yīng)的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)?//重點(diǎn)看這句
??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中執(zhí)行類型轉(zhuǎn)換實(shí)際上是調(diào)用的函數(shù)[mscorlib]System.Math::Round(float64),MSDN中對這個(gè)函數(shù)的解釋:將雙精度浮點(diǎn)值舍入為最接近的整數(shù),如果參數(shù)為兩個(gè)整數(shù)的中值,這兩個(gè)整數(shù)一個(gè)為偶數(shù),另一個(gè)為奇數(shù),則返回偶數(shù)(也就是我們常說的“四舍六入五成雙”)。
??????現(xiàn)在,可以很好的解釋文章開始提出的問題了:由于輸入18時(shí),oneTimeNum的值為2,當(dāng)循環(huán)到第16次時(shí)i = 15,此時(shí)執(zhí)行list.GetRange(oneTimeNum * i, length)即list.GetRange(30,2),已經(jīng)超出了list的長度范圍,所以會拋出異常。
??????4.C#和VB.NET的區(qū)別
??????1)C#中的除運(yùn)算"/"符相當(dāng)于VB.NET的整數(shù)除"/"運(yùn)算符;
????? 2)C#中從Double—>Integer類型轉(zhuǎn)換必須要采用顯示方式,且轉(zhuǎn)換規(guī)則為直接舍棄小數(shù)位。
????? 總結(jié)這次出現(xiàn)問題的根源是用C#語法去推斷VB.NET語法,因?yàn)榻佑|C#較早,而C#和VB.NET語法又大同小異,忽略了對VB.NET基本語法的學(xué)習(xí),以后應(yīng)多注意兩種語言的差別,盡量減少類似的錯(cuò)誤。還有一點(diǎn)需要注意,遇到問題的時(shí)候多查MSDN,似乎現(xiàn)在都習(xí)慣從網(wǎng)上尋求答案,但網(wǎng)上關(guān)于 VB.NET除運(yùn)算符的內(nèi)容并不多,找了半天,才發(fā)現(xiàn)MSDN上寫的很詳細(xì),我想查找資料的順序應(yīng)該是:MSDN—>CNBlogs找找看— >Google/Baidu。
Tag標(biāo)簽: C#,VB,運(yùn)算符,類型轉(zhuǎn)換
原文:http://www.cnblogs.com/freshman0216/archive/2008/08/27/1276991.html
與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖
總結(jié)
以上是生活随笔為你收集整理的小心VB.NET中的除运算符/和/的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。