5

假设我在函数中有一个静态变量:

Private Sub SomeFunction()
    Static staticVar As String = _myField.Value
End Sub

确切地说,值是什么时候_myField分配给的staticVar?在第一次调用该函数时?封闭类的实例化?

4

3 回答 3

10

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 只是一个简单的变量。仅当您不担心成本时才使用静态。

于 2012-08-30T17:30:58.913 回答
2

Static明显,变量在分配时会被实例化。

当那条线运行时,不是之前,不是之后。

在上面放一个断点,你会看到。

Static只是意味着该值将在调用之间保持不变。

Shared类/模块成员在第一次访问类时被实例化,在任何Shared构造函数之前和调用之前,无论是类构造函数还是某些Shared方法/属性。我想这可能是你困惑的根源。Static局部变量,如staticc# 中的 local s 不会以这种方式实例化。


来自 Tim Schmelter的有趣信息,该值似乎是使用隐藏的类级别变量在内部维护的,该Shared变量像其他Shared类级别变量一样被实例化,但始终使用默认值。

除了访问类时的一些实例化延迟之外,开发人员观察到的效果没有变化。这种延迟在实践中应该是检测不到的。

于 2012-08-30T15:05:26.537 回答
1

VB.NET 编译器创建一个静态(在 VB.NET 中共享)类级变量来维护“staticVar”的值。因此,它像任何其他静态/共享变量一样在第一次使用该类的静态字段时(或当您调用此方法时)进行初始化。

http://weblogs.asp.net/psteele/pages/7717.aspx

于 2012-08-30T15:06:37.710 回答