我在Reflector中查看LazyInitializer.EnsureInitialized(ref T, Func{T})
,并且该方法中似乎存在一个易变的局部变量volatile object local1 = s_barrier;
。我可以想到两个可能的原因:
.NET可能会使用给定语言不支持的功能,或者
实际代码没有声明一个易变的局部变量,但是当Reflector对编译后的代码进行反编译时,它看起来像一个易变的局部变量。
有谁知道这是哪种情况(或者是否有其他解释)?如果是反编译问题,是否有人知道“真正的”代码会是什么样的?
答案 0 :(得分:3)
这看起来像一个Reflector错误:它只是s_barrier
字段的普通易失性读取。这里没有“特殊”的IL,这在C#中是不可表达的。
L_000d: volatile.
L_000f: ldsfld object modreq(System.Runtime.CompilerServices.IsVolatile) System.Threading.LazyInitializer::s_barrier
这只是编译器从静态volatile字段读取时发出的正常代码。
这是一个更简单的repro:只需在 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#编译器优化了字段值(易失性读取的结果)到局部变量(stloc
指令)的赋值,因为本地不是随后使用。这似乎混淆了Reflector。如果您更改了方法以使用随后使用的local,那么确实会发出stloc
(或类似的)指令,然后反射器的反编译输出看起来很合理。
答案 1 :(得分:2)
Ani是对的。这是从Reference Source检索到的实际源代码。反射器很不错,但不能对实际注释的源代码持蜡烛。
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编写代码的快乐提出了一些见解。