VB.NET 的“If”是否有效?运营商造成拳击?

发布于 2024-08-24 15:17:09 字数 980 浏览 11 评论 0原文

我们这些曾经在 VB/VB.NET 工作过的人都见过类似这种令人厌恶的代码:

Dim name As String = IIf(obj Is Nothing, "", obj.Name)

我说“令人厌恶”是出于三个简单的原因:

  1. IIf 是一个函数,所有参数均被评估;因此,如果上述调用中 obj 没有任何内容,则将抛出 NullReferenceException 。对于习惯在 C# 等语言中使用短路三元运算符的人来说,这是意想不到的行为。
  2. 因为 IIf 是一个函数,因此会产生函数调用的开销。再说一次,虽然这不是什么大问题,但对于那些期望它表现为语言固有的三元运算的人来说,这感觉不太对劲。
  3. IIf 是非泛型的,因此接受 Object 类型的参数,这意味着以下调用框(我相信)总共三个整数:

    ' 框出第二个和第三个参数以及返回值'
    Dim value As Integer = IIf(condition, 1, -1)

现在,在 VB.NET 的某些较新版本中(我不确定数字是多少),If<引入了 /code> 运算符,其工作方式与 IIf 函数完全相同,但(据我所知)没有相同的缺点。也就是说,它确实提供短路并且它固有的VB操作。但是,我不确定最后一部分。 MSDN 文档似乎没有表明是否 If< /code> 是否装箱其参数。有谁知道吗?

Those of us who've worked in VB/VB.NET have seen code similar to this abomination:

Dim name As String = IIf(obj Is Nothing, "", obj.Name)

I say "abomination" for three simple reasons:

  1. IIf is a function, all of whose parameters are evaluated; hence if obj is nothing in the above call then a NullReferenceException will be thrown. This is unexpected behavior for someone who's accustomed to short-circuited ternary operators in languages like C#.
  2. Because IIf is a function, it thus incurs the overhead of a function call. Again, though this isn't a big deal, it just doesn't feel right to someone who expects for it to behave as a ternary operation intrinsic to the language.
  3. IIf is non-generic and therefore accepts parameters of type Object, which means the following call boxes (I believe) a total of three integers:

    ' boxes 2nd and 3rd arguments as well as return value '
    Dim value As Integer = IIf(condition, 1, -1)

Now, in some more recent version of VB.NET (I'm not sure what the number is), the If operator was introduced, which works exactly the same way as the IIf function but (as I understand it) without the same shortcomings. That is to say, it does provide short-circuiting and it is an intrinstic VB operation. However, I'm not sure about the last part. The MSDN documentation doesn't seem to indicate whether If boxes its arguments or not. Does anyone know?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

来世叙缘 2024-08-31 15:17:09

最主要的是您正确地将新的 If 识别为运算符而不是函数。它也是类型安全的,因此不需要装箱,并且是到条件/三元/? 的直接映射。 C/C++/C#/Java/etc 中的运算符

即使没有 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

The main thing is that you correctly identified the new If as an operator rather than a function. It is also typesafe and therefore does not need boxing, and is a direct mapping to the conditional/ternary/? operator in C/C++/C#/Java/etc

Even without the new operator, you can get some improvement in VB.Net with this code:

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
べ映画 2024-08-31 15:17:09

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

正如您所看到的,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 
}

给定相同的程序但使用旧的 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 
}

Joel beat me to an answer, but here is a sample program and the generated IL that demonstrates that If() passes through to the IL's underlying ternary operator without boxing.

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

As you can see the IL has no 'box' statement.

.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 
}

Given the same program but using the older IIf() function, the following IL is produced. You can see both the boxing, and the function call overhead:

.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 
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文