假设我在函数中有一个静态变量:
Private Sub SomeFunction()
Static staticVar As String = _myField.Value
End Sub
确切地说,值是什么时候_myField
分配给的staticVar
?在第一次调用该函数时?封闭类的实例化?
假设我在函数中有一个静态变量:
Private Sub SomeFunction()
Static staticVar As String = _myField.Value
End Sub
确切地说,值是什么时候_myField
分配给的staticVar
?在第一次调用该函数时?封闭类的实例化?
CLR 不支持此构造,因此 VB.NET 编译器模拟它。
先创作。该变量被提升到类的私有字段,其名称不可描述,以确保不会发生名称冲突。如果变量在类的实例方法中,它将是一个实例字段。So 将在使用new运算符创建类的对象时创建。如果方法是共享的或者是模块的一部分,它将是一个共享字段。所以会在加载器堆中由抖动创建。
作业接下来,涉及的操作要多得多。语言规则是当代码执行第一次到达 Dim 语句时发生赋值。第一次这个词是一个加载的。编译器在方法内部生成了大量代码,以确保这一点得到保证。需要解决的问题是线程、递归和异常。
编译器在与隐藏变量字段相同的范围内创建另一个StaticLocalInitFlag类型的隐藏助手字段,以跟踪变量的初始化状态。注入代码的第一部分是调用 Monitor.Enter() 来处理线程。与 SyncLock 相同。StaticLocalInitFlag 用作锁定对象,注意它是一个类而不仅仅是一个布尔值。
接下来,Try 和 finally 语句防止异常。在 Try 语句中,检查 StaticLocalInitFlag.State 的值是否为 0。这可以防止同一线程上的递归。然后将 State 设置为 2 以指示初始化代码正在运行。紧随其后的是任务。接下来,再次检查 State 以查看它是否仍为 2。如果不是,则出现严重错误并引发 IncompleteInitialization 异常。
finally 块然后将 State 设置为 1 以指示变量已初始化。随后调用 Monitor.Leave()。
大量代码,96 字节的 IL 只是一个简单的变量。仅当您不担心成本时才使用静态。
很Static
明显,变量在分配时会被实例化。
当那条线运行时,不是之前,不是之后。
在上面放一个断点,你会看到。
Static
只是意味着该值将在调用之间保持不变。
Shared
类/模块成员在第一次访问类时被实例化,在任何Shared
构造函数之前和调用之前,无论是类构造函数还是某些Shared
方法/属性。我想这可能是你困惑的根源。Static
局部变量,如static
c# 中的 local s 不会以这种方式实例化。
来自 Tim Schmelter的有趣信息,该值似乎是使用隐藏的类级别变量在内部维护的,该Shared
变量像其他Shared
类级别变量一样被实例化,但始终使用默认值。
除了访问类时的一些实例化延迟之外,开发人员观察到的效果没有变化。这种延迟在实践中应该是检测不到的。
VB.NET 编译器创建一个静态(在 VB.NET 中共享)类级变量来维护“staticVar”的值。因此,它像任何其他静态/共享变量一样在第一次使用该类的静态字段时(或当您调用此方法时)进行初始化。