Dan*_*Tao 18 vb.net boxing ternary-operator
我们这些在VB/VB.NET中工作的人看到的代码类似于这种令人厌恶的代码:
Dim name As String = IIf(obj Is Nothing, "", obj.Name)
Run Code Online (Sandbox Code Playgroud)
我说"憎恶"有三个简单的原因:
IIf
是一个函数,所有参数都被评估; 因此,如果obj
在上述调用中没有任何内容,那么NullReferenceException
将抛出一个.对于习惯于使用C#等语言的短路三元运算符的人来说,这是出乎意料的行为.IIf
是一个函数,所以它会产生函数调用的开销.同样,虽然这不是什么大问题,但对于那些期望它表现为语言固有的三元操作的人来说,这感觉不对.IIf
是非泛型的,因此接受类型的参数Object
,这意味着以下调用框(我相信)总共有三个整数:
' boxes 2nd and 3rd arguments as well as return value '
Dim value As Integer = IIf(condition, 1, -1)
现在,在一些更新版本的VB.NET中(我不确定数字是多少),If
引入了运算符,其IIf
功能与函数完全相同,但(据我所知)没有相同的缺点.也就是说,它确实提供了短路,并且它是一种内在的VB操作.但是,我不确定最后一部分.在MSDN文档似乎并没有表示是否If
箱及其参数与否.有人知道吗?
Joe*_*orn 12
主要的是你正确地将new标识If
为运算符而不是函数.它也是类型安全的,因此不需要装箱,并且是直接映射到条件/三元/?C/C++/C#/ Java /等中的运算符
即使没有new运算符,您也可以使用以下代码在VB.Net中获得一些改进:
Public Shared Function IIf(Of T)(ByVal Expression As Boolean, ByVal TruePart As T, ByVal FalsePart As T) As T
If Expression Then Return TruePart Else Return FalsePart
End Function
Run Code Online (Sandbox Code Playgroud)
Jim*_*nts 11
Joel打败了我的回答,但是这里有一个示例程序和生成的IL,它演示了If()在没有装箱的情况下传递给IL的底层三元运算符.
Public Class Test
Public Sub New()
Dim rnd = New Random()
Dim result As Integer = If(rnd.Next(1000) < 500, 1, -1)
Console.WriteLine(result)
End Sub
End Class
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,IL没有'box'语句.
.method public specialname rtspecialname instance void .ctor() cil managed
{
.maxstack 2
.locals init (
[0] int32 result,
[1] class [mscorlib]System.Random rnd)
L_0000: nop
L_0001: ldarg.0
L_0002: call instance void [mscorlib]System.Object::.ctor()
L_0007: nop
L_0008: newobj instance void [mscorlib]System.Random::.ctor()
L_000d: stloc.1
L_000e: ldloc.1
L_000f: ldc.i4 0x3e8
L_0014: callvirt instance int32 [mscorlib]System.Random::Next(int32)
L_0019: ldc.i4 500
L_001e: blt.s L_0023
L_0020: ldc.i4.m1
L_0021: br.s L_0024
L_0023: ldc.i4.1
L_0024: stloc.0
L_0025: ldloc.0
L_0026: call void [mscorlib]System.Console::WriteLine(int32)
L_002b: nop
L_002c: nop
L_002d: ret
}
Run Code Online (Sandbox Code Playgroud)
给定相同的程序但使用较旧的IIf()函数,生成以下IL.你可以看到装箱和函数调用开销:
.method public specialname rtspecialname instance void .ctor() cil managed
{
.maxstack 3
.locals init (
[0] int32 result,
[1] class [mscorlib]System.Random rnd)
L_0000: nop
L_0001: ldarg.0
L_0002: call instance void [mscorlib]System.Object::.ctor()
L_0007: nop
L_0008: newobj instance void [mscorlib]System.Random::.ctor()
L_000d: stloc.1
L_000e: ldloc.1
L_000f: ldc.i4 0x3e8
L_0014: callvirt instance int32 [mscorlib]System.Random::Next(int32)
L_0019: ldc.i4 500
L_001e: clt
L_0020: ldc.i4.1
L_0021: box int32
L_0026: ldc.i4.m1
L_0027: box int32
L_002c: call object [Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::IIf(bool, object, object)
L_0031: call int32 [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Conversions::ToInteger(object)
L_0036: stloc.0
L_0037: ldloc.0
L_0038: call void [mscorlib]System.Console::WriteLine(int32)
L_003d: nop
L_003e: nop
L_003f: ret
}
Run Code Online (Sandbox Code Playgroud)