C# C“实际上并没有复制整个”;“大结构”;从IL看传递论点?

C# C“实际上并没有复制整个”;“大结构”;从IL看传递论点?,c#,compilation,C#,Compilation,我经常听说,对于值类型,我们在将它们传递到方法中时必须小心,因为值将被复制。如果结构很大,那么可能是个问题 不过,我看了一下这段代码的IL: using System; public class Program { public struct Big { public int a, b, c, d; } public static void Main() { Big big = new Big(); Us

我经常听说,对于值类型,我们在将它们传递到方法中时必须小心,因为值将被复制。如果结构很大,那么可能是个问题

不过,我看了一下这段代码的IL:

using System;

public class Program
{
    public struct Big
    {
        public int a, b, c, d;
    }

    public static void Main()
    {
        Big big = new Big();
        UseBig(big);
        big.a += 7;
    }

    private static void UseBig(Big big)
    {
        big.a += 1;
        big.b += 1;
    }
}
IL:

调用函数的机制是,它
将局部变量#0
的位置加载到堆栈中,然后在函数内部使用
加载参数的地址
。然后我们可以使用这个地址
加载字段
存储字段
dup
因为
load
store
将使用堆栈顶部的地址

使用
ref
再次运行:

using System;

public class Program
{
    public struct Big
    {
        public int a, b, c, d;
    }

    public static void Main()
    {
        Big big = new Big();
        UseBig(ref big);
        big.a += 7;
    }

    private static void UseBig(ref Big big)
    {
        big.a += 1;
        big.b += 1;
    }
}
IL:

在输入函数时,它使用
load local variable address
来代替它的值,因此地址进入函数内部,而不是加载它的地址,因为它已经是一个地址,所以我们直接
加载参数
值。我们在这里所做的一切都会影响调用者的值,因为它是对调用者的地址而不是参数变量空间进行的。因此这就是
ref
的行为

问题是:

  • 所以实际上它并不依赖于我的
    struct
    c
    d
    )中的任何其他变量?不管它有多大,程序实际上是以单个地址的形式传递整个结构。那么人们一直在谈论的巨大成本在哪里呢
  • 在引擎盖下
    ref
    实际上并没有节省任何“结构复制成本”

  • 这些IL代码从第一版中获得,副本由

    ldloc.0
    
    没有传递给函数的地址


    无论如何,您不能依赖IL检查来实现这一点,请尝试查看生成的本机代码。即使在第一种情况下,内联也可能发生并优化掉该副本。

    在第一个版本中,副本由

    ldloc.0
    
    没有传递给函数的地址


    无论如何,您不能依赖IL检查来实现这一点,请尝试查看生成的本机代码。即使在第一种情况下,内联也可能发生并优化掉该副本。

    也许这取决于实际的结构大小,但您的大小并没有那么大。通常在编程中,风险是由于过度推送堆栈上的项或递归而耗尽堆栈。第一个堆栈具有“load local#0”而不是“load location(address)of local#0”@MickyD那么你是说,如果我有1000个
    long
    而不是4个
    int
    ,即使我只使用前2个变量,IL也会改变?好吧,我自己错过了副本。也许这取决于实际的结构大小,你的没有那么大。通常在编程中,风险是由于过度推送堆栈上的项或递归而耗尽堆栈。第一个堆栈具有“load local#0”而不是“load location(address)of local#0”@MickyD那么你是说,如果我有1000个
    long
    而不是只有4个
    int
    ,即使我只使用前2个变量,IL也会发生变化?好吧,我自己也错过了副本。。
    ldloc.0