代码之家  ›  专栏  ›  技术社区  ›  tigrou

调用方法并将返回值赋给数组时,为什么C#在调用方法时使用数组引用?

  •  -1
  • tigrou  · 技术社区  · 6 年前

    我有以下C#程序:

    class Program
    { 
        static int[] foo = new int[1];
    
        static void Main()
        {
            foo[0] = Get();
            Console.WriteLine(foo[0]); //print "0"
        }
    
        static int Get()
        {
            foo = new int[1];
            return 5;
        }
    }
    

    之后 Get() 已从调用 Main() ,我想 foo 要包含的数组 5 在第一个位置。然而,它是零。为什么会这样?

    这就像C#捕获对 foo公司 什么时候 获取() 方法被调用。 然后使用此旧数组引用指定 获取() 返回值(而不是中实例化的新值 获取() ).

    1 回复  |  直到 6 年前
        1
  •  5
  •   Marc Gravell    6 年前

    这个 操作数 in语句总是从左到右求值,即使 操作员 然后决定事情是怎样的 已处理 导致复杂的逻辑。这意味着 foo[0] 实际执行目标 之前 呼叫 Get 。您可以在IL中看到这一点:

    .method private hidebysig static 
        void Main () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 25 (0x19)
        .maxstack 8
    
        IL_0000: ldsfld int32[] Program::foo
        IL_0005: ldc.i4.0
        IL_0006: call int32 Program::Get()
        IL_000b: stelem.i4
        IL_000c: ldsfld int32[] Program::foo
        IL_0011: ldc.i4.0
        IL_0012: ldelem.i4
        IL_0013: call void [mscorlib]System.Console::WriteLine(int32)
        IL_0018: ret
    } // end of method Program::Main
    

    请注意 ldsfld ... foo ldc.i4.0 (常数零)执行 之前 这个 call ... Get() ,将这些值保留在堆栈上,以便在以后的 ldsfld。。。foo公司 。在更复杂的情况下(包括括号等),可以很有趣地看到编译器用于保留从左到右求值的技巧。像sharplab这样的工具可以帮助实现这一点; here's your example in sharplab

    这是由于ECMA 334规范中有12.4个操作员:

    12.4.1概述

    。。。

    表达式中运算符的求值顺序由运算符的优先级和关联性决定(§12.4.2)。

    表达式中的操作数从左到右求值。 [示例: 在F(i)+G(i++)*H(i)中,使用i的旧值调用方法F,然后使用i的旧值调用方法G,最后使用i的新值调用方法H。这与运算符优先级无关,也与运算符优先级无关。 结束示例]