Это похоже на ошибку в разборке Reflector C #.
Начиная с этого кода:
public static string _test;
public static string _setting;
public static string Test_1
{
get { return _test ?? (_setting ?? "default"); }
}
Отражатель показывает эту разборку C #:
public static string Test_1
{
get
{
return (_test ?? (_setting ?? "default"));
}
}
и соответствующий IL:
.method public hidebysig specialname static string get_Test_1() cil managed
{
.maxstack 8
L_0000: ldsfld string ConsoleApplication1.Program::_test
L_0005: dup
L_0006: brtrue.s L_0017
L_0008: pop
L_0009: ldsfld string ConsoleApplication1.Program::_setting
L_000e: dup
L_000f: brtrue.s L_0017
L_0011: pop
L_0012: ldstr "default"
L_0017: ret
}
Я не эксперт по IL, но это мое мнение:
L_0000:
ldsfld
помещает _test
в стек оценки
L_0005:
dup
копирует значение (_test
), которое является самым верхним в стеке оценки, и помещает его в стек.
L_0006:
brtrue.s
выталкивает значение, созданное dup
из стека, и переходит на L_0017
, если оно не null
.
L_0008:
pop
на данный момент, _test
равно null
, поэтому вытолкните это значение из стека.
и он продолжает оценивать _setting
аналогичным образом, в конечном итоге возвращая "default"
, если _setting
также null
.
Теперь, если мы добавим присвоение в код, как это:
public static string Test_2
{
get { return _test ?? (_test = (_setting ?? "default")); }
}
Отражатель показывает эту разборку C #:
public static string Test_2
{
get
{
if (_test == null)
{
string text1 = _test;
}
return (_test = _setting ?? "default");
}
}
, что неверно (если _test
не null
, вместо возврата _test
он присваивает _setting
или "default"
_test
и затем возвращает).
Однако, разборка IL выглядит как IL для Test_1
, с парой дополнительных инструкций в L_0017
и L_0018
для выполнения назначения.
.method public hidebysig specialname static string get_Test_2() cil managed
{
.maxstack 8
L_0000: ldsfld string ConsoleApplication1.Program::_test
L_0005: dup
L_0006: brtrue.s L_001d
L_0008: pop
L_0009: ldsfld string ConsoleApplication1.Program::_setting
L_000e: dup
L_000f: brtrue.s L_0017
L_0011: pop
L_0012: ldstr "default"
L_0017: dup
L_0018: stsfld string ConsoleApplication1.Program::_test
L_001d: ret
}
Наконец, если вы скопируете сборку Reflector C # и запустите ее на оригинале, вы увидите, что она дает другие результаты.
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
_test = "Test";
Console.WriteLine(Test_2);
Console.WriteLine(Reflector_Test_2);
Console.ReadLine();
}
public static string _test;
public static string _setting;
public static string Test_1
{
get { return _test ?? (_setting ?? "default"); }
}
public static string Test_2
{
get { return _test ?? (_test = (_setting ?? "default")); }
}
public static string Reflector_Test_2
{
get
{
if (_test == null)
{
string text1 = _test;
}
return (_test = _setting ?? "default");
}
}
}
}
Выходы
Test
default