[VB.Net] If vs IIf ,兩者的差異
這次的文章算隨筆
純粹是我之前印象 VB 的單行式判斷式 IIf 在某些狀況下是會有問題的,結果看到了公司的 Code 中有單行式判斷式 - If ,本來以為是類似 Alias 的東西,不過仔細探究才發現兩者的作法並不一樣
這裡稍微講述一下我之前對 IIf 的例外狀況的印象,首先 IIf 的格式是長這樣
IIf(Expression As Boolean, TruePart As Object, FalsePart As Object) As Object
當 Expression 為 True ,則回傳 TruePart ,否則則回傳 FalsePart 的部份
這看起來很直覺,感覺沒什麼問題,那我說的狀況是怎樣呢?
如果 TruePart 或 FalsePart 為一函式的呼叫,而如果 Expression 為 True 時,FalsePart 的函式則不能呼叫的狀況
舉例來說,如果 Expression 判斷某個變數值是否是 Nothing ,而 FalsePart 呼叫的函式會在該變數值為 Nothing 被呼叫的話,就會產生 Exception
至此,應該知道我說的狀況是什麼了?是的,就是其實 IIf 是函式,他是會將 TruePart 及 FalsePart 上的函式先進行評估運算後進行呼叫
實際可以以以下程式碼作測試:
Sub Main()
Dim bln As Boolean = True
Console.WriteLine(IIf(bln, A(), B()))
Console.WriteLine("====================================")
Console.WriteLine(If(bln, A(), B()))
End Sub
Function A() As String
Console.WriteLine("A()")
Return "A"
End Function
Function B() As String
Console.WriteLine("B()")
Return "B"
End Function
你會發現輸出的結果為:
A()
B()
A
====================================
A()
A
是的, If 這個呼叫並不像 IIf 是呼叫函式,而是編譯器在編譯階段會對其作處理,他是與 C-Like 的 ? : 同樣的作法的!
上面的程式碼進行 IL disassembly 後可以得到以下的結果:
.custom instance void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.StandardModuleAttribute::.ctor()
.method public static string A() cil managed
{
.maxstack 1
.locals init (
[0] string str)
L_0000: nop
L_0001: ldstr "A()"
L_0006: call void [mscorlib]System.Console::WriteLine(string)
L_000b: nop
L_000c: ldstr "A"
L_0011: stloc.0
L_0012: br.s L_0014
L_0014: ldloc.0
L_0015: ret
}
.method public static string B() cil managed
{
.maxstack 1
.locals init (
[0] string str)
L_0000: nop
L_0001: ldstr "B()"
L_0006: call void [mscorlib]System.Console::WriteLine(string)
L_000b: nop
L_000c: ldstr "B"
L_0011: stloc.0
L_0012: br.s L_0014
L_0014: ldloc.0
L_0015: ret
}
.method public static void Main() cil managed
{
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
.entrypoint
.maxstack 3
.locals init (
[0] bool flag)
L_0000: nop
L_0001: ldc.i4.1
L_0002: stloc.0
L_0003: ldloc.0
L_0004: call string WCT.aEnrich.TEST.Module1::A()
L_0009: call string WCT.aEnrich.TEST.Module1::B()
L_000e: call object [Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::IIf(bool, object, object)
L_0013: call object [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::GetObjectValue(object)
L_0018: call void [mscorlib]System.Console::WriteLine(object)
L_001d: nop
L_001e: ldstr "===================================="
L_0023: call void [mscorlib]System.Console::WriteLine(string)
L_0028: nop
L_0029: ldloc.0
L_002a: brtrue.s L_0033
L_002c: call string WCT.aEnrich.TEST.Module1::B()
L_0031: br.s L_0038
L_0033: call string WCT.aEnrich.TEST.Module1::A()
L_0038: call void [mscorlib]System.Console::WriteLine(string)
L_003d: nop
L_003e: nop
L_003f: ret
}
從 IL 中可以很明確的看出 IIf 是去呼叫 Microsoft.VisualBasic.Interaction.IIf 這個函式的
而 If 則是最基本的判斷如果變數值是 true ,則跳進 L_0033 ,否則繼續執行,並於 L_0031 時跳至 L_0038
所以兩者在根本上的運作是不同的!
建議更改習慣,減少使用 IIf ,使用 If 來取代 IIf
除非你會希望判斷式判斷式,兩個函式都要執行,但依據其結果,只回傳 TruePart 或 FalsePart 其中一邊的結果,那就可以繼續使用 IIf!
純粹是我之前印象 VB 的單行式判斷式 IIf 在某些狀況下是會有問題的,結果看到了公司的 Code 中有單行式判斷式 - If ,本來以為是類似 Alias 的東西,不過仔細探究才發現兩者的作法並不一樣
這裡稍微講述一下我之前對 IIf 的例外狀況的印象,首先 IIf 的格式是長這樣
IIf(Expression As Boolean, TruePart As Object, FalsePart As Object) As Object
當 Expression 為 True ,則回傳 TruePart ,否則則回傳 FalsePart 的部份
這看起來很直覺,感覺沒什麼問題,那我說的狀況是怎樣呢?
如果 TruePart 或 FalsePart 為一函式的呼叫,而如果 Expression 為 True 時,FalsePart 的函式則不能呼叫的狀況
舉例來說,如果 Expression 判斷某個變數值是否是 Nothing ,而 FalsePart 呼叫的函式會在該變數值為 Nothing 被呼叫的話,就會產生 Exception
至此,應該知道我說的狀況是什麼了?是的,就是其實 IIf 是函式,他是會將 TruePart 及 FalsePart 上的函式先進行評估運算後進行呼叫
實際可以以以下程式碼作測試:
Sub Main()
Dim bln As Boolean = True
Console.WriteLine(IIf(bln, A(), B()))
Console.WriteLine("====================================")
Console.WriteLine(If(bln, A(), B()))
End Sub
Function A() As String
Console.WriteLine("A()")
Return "A"
End Function
Function B() As String
Console.WriteLine("B()")
Return "B"
End Function
你會發現輸出的結果為:
A()
B()
A
====================================
A()
A
是的, If 這個呼叫並不像 IIf 是呼叫函式,而是編譯器在編譯階段會對其作處理,他是與 C-Like 的 ? : 同樣的作法的!
上面的程式碼進行 IL disassembly 後可以得到以下的結果:
.custom instance void [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.StandardModuleAttribute::.ctor()
.method public static string A() cil managed
{
.maxstack 1
.locals init (
[0] string str)
L_0000: nop
L_0001: ldstr "A()"
L_0006: call void [mscorlib]System.Console::WriteLine(string)
L_000b: nop
L_000c: ldstr "A"
L_0011: stloc.0
L_0012: br.s L_0014
L_0014: ldloc.0
L_0015: ret
}
.method public static string B() cil managed
{
.maxstack 1
.locals init (
[0] string str)
L_0000: nop
L_0001: ldstr "B()"
L_0006: call void [mscorlib]System.Console::WriteLine(string)
L_000b: nop
L_000c: ldstr "B"
L_0011: stloc.0
L_0012: br.s L_0014
L_0014: ldloc.0
L_0015: ret
}
.method public static void Main() cil managed
{
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
.entrypoint
.maxstack 3
.locals init (
[0] bool flag)
L_0000: nop
L_0001: ldc.i4.1
L_0002: stloc.0
L_0003: ldloc.0
L_0004: call string WCT.aEnrich.TEST.Module1::A()
L_0009: call string WCT.aEnrich.TEST.Module1::B()
L_000e: call object [Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::IIf(bool, object, object)
L_0013: call object [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::GetObjectValue(object)
L_0018: call void [mscorlib]System.Console::WriteLine(object)
L_001d: nop
L_001e: ldstr "===================================="
L_0023: call void [mscorlib]System.Console::WriteLine(string)
L_0028: nop
L_0029: ldloc.0
L_002a: brtrue.s L_0033
L_002c: call string WCT.aEnrich.TEST.Module1::B()
L_0031: br.s L_0038
L_0033: call string WCT.aEnrich.TEST.Module1::A()
L_0038: call void [mscorlib]System.Console::WriteLine(string)
L_003d: nop
L_003e: nop
L_003f: ret
}
從 IL 中可以很明確的看出 IIf 是去呼叫 Microsoft.VisualBasic.Interaction.IIf 這個函式的
而 If 則是最基本的判斷如果變數值是 true ,則跳進 L_0033 ,否則繼續執行,並於 L_0031 時跳至 L_0038
所以兩者在根本上的運作是不同的!
建議更改習慣,減少使用 IIf ,使用 If 來取代 IIf
除非你會希望判斷式判斷式,兩個函式都要執行,但依據其結果,只回傳 TruePart 或 FalsePart 其中一邊的結果,那就可以繼續使用 IIf!
留言
張貼留言