LazyInitializer.EnsureInitialized中的Volatile局部变量
本文关键字:局部变量 Volatile 中的 EnsureInitialized LazyInitializer | 更新日期: 2023-09-27 18:19:09
我在Reflector中查看LazyInitializer.EnsureInitialized(ref T, Func{T})
,并且该方法volatile object local1 = s_barrier;
中似乎有一个易失性的局部变量. 我可以想到两个可能的原因:
-
。. NET可能会使用给定语言不支持的特性,或者
-
实际代码没有声明一个易失性局部变量,但是当编译后的代码被Reflector反编译时,它看起来像一个易失性局部变量。
有谁知道这里是哪种情况(或者是否可能有其他解释)?如果这是一个反编译的问题,有人知道"真正的"代码应该是什么样子吗?
这看起来像一个反射器的错误:它只是一个正常的易失性读取的s_barrier
字段。这里没有不能在c#中表达的"特殊"IL。
L_000d: volatile.
L_000f: ldsfld object modreq(System.Runtime.CompilerServices.IsVolatile) System.Threading.LazyInitializer::s_barrier
这只是编译器从静态volatile字段读取时发出的正常代码。
这里有一个更简单的复制:只需以release模式编译以下代码(用类型包装):
private static volatile object field;
private static void Main()
{
var temp = field;
}
Reflector生成以下反编译c#:
private static void Main()
{
volatile object field = Program.field;
}
当IL实际上是:
L_0000: volatile.
L_0002: ldsfld object modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) WindowsFormsApplication1.Program::field
L_0007: pop
L_0008: ret
:以下是我对发生的事情的猜测:在发布模式下,c#编译器优化了将字段的值(volatile read的结果)赋值给局部变量(stloc
指令),因为随后不使用局部变量。这似乎混淆了Reflector。如果您将方法更改为使用随后的use局部,则确实会发出stloc
(或类似的)指令,然后从Reflector反编译的输出看起来是合理的。
阿尼是对的。这是从参考源中检索到的实际源代码。反射器很好,但不能与实际注释的源代码相提并论。
public static T EnsureInitialized<T>(ref T target) where T : class
{
// Fast path.
if (target != null)
{
object barrierGarbage = s_barrier; // Insert a volatile load barrier. Needed on IA64.
return target;
}
return EnsureInitializedCore<T>(ref target, LazyHelpers<T>.s_activatorFactorySelector);
}
这个命名的选择也让我们了解了微软程序员是如何看待为Titanium编写代码的乐趣的。