gpt4 book ai didi

vb.net - 'With ... End With' 真的更高效吗?

转载 作者:行者123 更新时间:2023-12-02 06:40:29 25 4
gpt4 key购买 nike

所以我在玩 ILDASM 时发现了一个奇怪的现象,我在 Google 上找不到很好的解释。

似乎在 VB.NET 中使用 With block 时,生成的 MSIL 比 w/o 更大。所以这让我想问,With Blocks 真的更高效吗? MSIL 是 JIT 到 native 机器代码中的工具,因此较小的代码大小应该意味着更高效的代码,对吗?

下面是两个类(Class2 和 Class3)的示例,它们为 Class1 的实例设置相同的值。 Class2 不使用 With block 来完成此操作,而 Class3 使用 With block 。 Class1 有 6 个属性,涉及 6 个私有(private)成员。每个成员都具有特定的数据类型,并且都是此测试用例的一部分。

Friend Class Class2
Friend Sub New()
Dim c1 As New Class1

c1.One = "foobar"
c1.Two = 23009
c1.Three = 3987231665
c1.Four = 2874090071765301873
c1.Five = 3.1415973801462975
c1.Six = "a"c
End Sub
End Class

Friend Class Class3
Friend Sub New()
Dim c1 As New Class1

With c1
.One = "foobar"
.Two = 23009
.Three = 3987231665
.Four = 2874090071765301873
.Five = 3.1415973801462975
.Six = "a"c
End With
End Sub
End Class

这是 Class2 的最终 MSIL:

.method assembly specialname rtspecialname 
instance void .ctor() cil managed
{
// Code size 84 (0x54)
.maxstack 2
.locals init ([0] class WindowsApplication1.Class1 c1)
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: newobj instance void WindowsApplication1.Class1::.ctor()
IL_000b: stloc.0
IL_000c: ldloc.0
IL_000d: ldstr "foobar"
IL_0012: callvirt instance void WindowsApplication1.Class1::set_One(string)
IL_0017: ldloc.0
IL_0018: ldc.i4 0x59e1
IL_001d: callvirt instance void WindowsApplication1.Class1::set_Two(int16)
IL_0022: ldloc.0
IL_0023: ldc.i4 0xeda853b1
IL_0028: callvirt instance void WindowsApplication1.Class1::set_Three(uint32)
IL_002d: ldloc.0
IL_002e: ldc.i8 0x27e2d1b1540c3a71
IL_0037: callvirt instance void WindowsApplication1.Class1::set_Four(uint64)
IL_003c: ldloc.0
IL_003d: ldc.r8 3.1415973801462975
IL_0046: callvirt instance void WindowsApplication1.Class1::set_Five(float64)
IL_004b: ldloc.0
IL_004c: ldc.i4.s 97
IL_004e: callvirt instance void WindowsApplication1.Class1::set_Six(char)
IL_0053: ret
} // end of method Class2::.ctor

这是 Class3 的 MSIL:

.method assembly specialname rtspecialname 
instance void .ctor() cil managed
{
// Code size 88 (0x58)
.maxstack 2
.locals init ([0] class WindowsApplication1.Class1 c1,
[1] class WindowsApplication1.Class1 VB$t_ref$L0)
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: newobj instance void WindowsApplication1.Class1::.ctor()
IL_000b: stloc.0
IL_000c: ldloc.0
IL_000d: stloc.1
IL_000e: ldloc.1
IL_000f: ldstr "foobar"
IL_0014: callvirt instance void WindowsApplication1.Class1::set_One(string)
IL_0019: ldloc.1
IL_001a: ldc.i4 0x59e1
IL_001f: callvirt instance void WindowsApplication1.Class1::set_Two(int16)
IL_0024: ldloc.1
IL_0025: ldc.i4 0xeda853b1
IL_002a: callvirt instance void WindowsApplication1.Class1::set_Three(uint32)
IL_002f: ldloc.1
IL_0030: ldc.i8 0x27e2d1b1540c3a71
IL_0039: callvirt instance void WindowsApplication1.Class1::set_Four(uint64)
IL_003e: ldloc.1
IL_003f: ldc.r8 3.1415973801462975
IL_0048: callvirt instance void WindowsApplication1.Class1::set_Five(float64)
IL_004d: ldloc.1
IL_004e: ldc.i4.s 97
IL_0050: callvirt instance void WindowsApplication1.Class1::set_Six(char)
IL_0055: ldnull
IL_0056: stloc.1
IL_0057: ret
} // end of method Class3::.ctor

我一眼就能看出的唯一主要区别是 ldloc.1 的使用操作码 ldloc.0 。根据 MSDN,这两者之间的差异可以忽略不计,ldloc.0是一种有效的使用方法ldloc访问索引 0 处的局部变量,以及 ldloc.1相同,只是索引 1。

请注意,Class3 的代码大小是 88 与 84。这些来自发布/优化版本。内置 VB Express 2010、.NET 4.0 Framework 客户端配置文件。

想法?

编辑:
我想为那些在这个帖子上遇到困难的人添加我所理解的答案的一般要点。

合理使用With ... End With :

With ObjectA.Property1.SubProperty7.SubSubProperty4
.SubSubSubProperty1 = "Foo"
.SubSubSubProperty2 = "Bar"
.SubSubSubProperty3 = "Baz"
.SubSubSubProperty4 = "Qux"
End With

不合理地使用 With ... End With :

With ObjectB
.Property1 = "Foo"
.Property2 = "Bar"
.Property3 = "Baz"
.Property4 = "Qux"
End With

原因是因为在 ObjectA 的示例中,您将删除多个成员,并且该成员的每个解析都需要一些工作,因此只需解析一次引用并将最终引用粘贴到临时变量中(这就是全部) With 确实如此),这可以加快访问隐藏在该对象深处的属性/方法的速度。

ObjectB 效率不高,因为您只深入一层。每个分辨率与访问 With 创建的临时引用大致相同。声明,因此性能几乎没有提升。

最佳答案

查看 IL 代码,With block 的作用基本上是:

Friend Class Class3
Friend Sub New()
Dim c1 As New Class1
Dim temp as Class1 = c1
temp.One = "foobar"
temp.Two = 23009
temp.Three = 3987231665
temp.Four = 2874090071765301873
temp.Five = 3.1415973801462975
temp.Six = "a"c
temp = Nothing
End Sub
End Class

但重要的是 JIT 编译器如何处理它。语言编译器没有做太多优化,这主要留给 JIT 编译器。最有可能的是,它会发现变量 c1 除了创建另一个变量之外没有用于任何其他用途,并完全优化 c1 的存储。

无论哪种方式,如果它仍然创建另一个变量,那都是一个非常便宜的操作。即使有任何性能差异,也非常小,并且可能会下降。

关于vb.net - 'With ... End With' 真的更高效吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4094378/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com