问候!我对C#编译器如何执行其优化感到有些困惑。
我编写了以下getter来组成“惰性”初始化,如果为null,则使用默认值:

静态类助手:

private static string host;
public static string Host
{
    get
    {
        return host ?? (host= (ConfigurationManager.AppSettings["Host"] ?? "host.ru"));
    }
}


这是Reflector拆卸的结果:

public static string Host
{
    get
    {
        if (Helper.host == null)
        {
            string host = Helper.host;
        }
        return (Helper.host = ConfigurationManager.AppSettings["Host"] ?? "host.ru");
    }
}


看起来它可以以其他方式工作...

更新

    private static string host;
    public static string Host
    {
        get
        {
            return host ?? (host = (GetVal() ?? "default"));
        }
    }
    static void Main(string[] args)
    {

        Console.WriteLine(Host);
        host = "overwritten";
        Console.WriteLine(Host);
    }
    static string GetVal()
    {
        return "From config";
    }


正常工作(从配置中覆盖),但是Reflector显示相同:

public static string Host
{
    get
    {
        if (Program.host == null)
        {
            string host = Program.host;
        }
        return (Program.host = GetVal() ?? "default");
    }
}

最佳答案

这看起来像是Reflector的C#反汇编中的错误。

从以下代码开始:

public static string _test;
public static string _setting;

public static string Test_1
{
    get { return _test ?? (_setting ?? "default"); }
}


Reflector显示此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.sdup创建的值弹出堆栈,如果不是L_0017,则跳转到null
L_0008: pop此时,_testnull,因此将该值弹出堆栈。


并继续以类似的方式评估_setting,如果"default"也是_setting,则最终返回null

现在,如果我们将赋值添加到代码中,如下所示:

public static string Test_2
{
    get { return _test ?? (_test = (_setting ?? "default")); }
}


Reflector显示此C#反汇编:

public static string Test_2
{
    get
    {
        if (_test == null)
        {
            string text1 = _test;
        }
        return (_test = _setting ?? "default");
    }
}


这是不正确的(如果_test不是null,而不是返回_test,而是将_setting"default"分配给_test,然后返回)。

但是,IL反汇编看起来像Test_1的IL,在L_0017L_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

关于c# - C#编译优化:空合并运算符-更新-Reflector的错误?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4292142/

10-12 03:40