访问struct字段会复制整个结构吗?

时间:2016-08-25 04:47:52

标签: c# struct

我知道将结构作为参数传递给方法,返回它们,或者尝试将struct值赋给变量会创建整个结构的副本。

现在,看看下面的假设代码:

//Regions is an array of a struct type. Color and r/g/b are structs too.

if(Regions[0].Color.r == Regions[0].Color.g && Regions[0].Color.b != 0){
  .
  ..      
}

要获得 r / g / b 值,会在幕后发生什么?只有 r / g / b 值被复制到内存位置或整个Regions [0]三次?

2 个答案:

答案 0 :(得分:1)

我认为此代码会复制您所询问的内容:

void Main()
{
    var foos = new Foo[]
    {
        new Foo() { Color = System.Drawing.Color.Red },
    };

    if (foos[0].Color.R == 45 && foos[0].Color.B == 55)
    {
        Console.WriteLine("!");
    }
}

public struct Foo
{
    public System.Drawing.Color Color;
}

IL产生的是:

IL_0000:  ldc.i4.1    
IL_0001:  newarr      Foo
IL_0006:  dup         
IL_0007:  ldc.i4.0    
IL_0008:  ldloca.s    01 
IL_000A:  initobj     Foo
IL_0010:  ldloca.s    01 
IL_0012:  call        System.Drawing.Color.get_Red
IL_0017:  stfld       Foo.Color
IL_001C:  ldloc.1     
IL_001D:  stelem      Foo
IL_0022:  stloc.0     // foos
IL_0023:  ldloc.0     // foos
IL_0024:  ldc.i4.0    
IL_0025:  ldelema     Foo
IL_002A:  ldflda      Foo.Color
IL_002F:  call        System.Drawing.Color.get_R
IL_0034:  ldc.i4.s    2D 
IL_0036:  bne.un.s    IL_0057
IL_0038:  ldloc.0     // foos
IL_0039:  ldc.i4.0    
IL_003A:  ldelema     Foo
IL_003F:  ldflda      Foo.Color
IL_0044:  call        System.Drawing.Color.get_B
IL_0049:  ldc.i4.s    37 
IL_004B:  bne.un.s    IL_0057
IL_004D:  ldstr       "!"
IL_0052:  call        System.Console.WriteLine
IL_0057:  ret         

您会注意到ldelemaldflda操作码的两个批次。两者都只是传递参考文献。

所以,你制作两份副本。一切都通过参考传递。

答案 1 :(得分:0)

Region是一个结构数组。我做了一个快速的例子来检查生成的IL:

public class Program
{

    public static void Main()
    {
        Foo[] Regions = new Foo[10];

        Regions[0] = new Foo();


        if(Regions[0].Color.R == Regions[0].Color.G && Regions[0].Color.B != 0)
        {

        }


    }
}

public struct Foo
{
    public Color Color { set; get; }
}

正如您在get_Color下面生成的IL中看到的那样被调用3次,因此Color的值被复制3次并被检索。

  .method public hidebysig static void  Main() cil managed
  {
    // 
    .maxstack  3
    .locals init (valuetype Foo[] V_0,
             valuetype [System.Drawing]System.Drawing.Color V_1,
             bool V_2)
    IL_0000:  nop
    IL_0001:  ldc.i4.s   10
    IL_0003:  newarr     Foo
    IL_0008:  stloc.0
    IL_0009:  ldloc.0
    IL_000a:  ldc.i4.0
    IL_000b:  ldelema    Foo
    IL_0010:  initobj    Foo
    IL_0016:  ldloc.0
    IL_0017:  ldc.i4.0
    IL_0018:  ldelema    Foo
    IL_001d:  call       instance valuetype [System.Drawing]System.Drawing.Color Foo::get_Color()
    IL_0022:  stloc.1
    IL_0023:  ldloca.s   V_1
    IL_0025:  call       instance uint8 [System.Drawing]System.Drawing.Color::get_R()
    IL_002a:  ldloc.0
    IL_002b:  ldc.i4.0
    IL_002c:  ldelema    Foo
    IL_0031:  call       instance valuetype [System.Drawing]System.Drawing.Color Foo::get_Color()
    IL_0036:  stloc.1
    IL_0037:  ldloca.s   V_1
    IL_0039:  call       instance uint8 [System.Drawing]System.Drawing.Color::get_G()
    IL_003e:  bne.un.s   IL_0059

    IL_0040:  ldloc.0
    IL_0041:  ldc.i4.0
    IL_0042:  ldelema    Foo
    IL_0047:  call       instance valuetype [System.Drawing]System.Drawing.Color Foo::get_Color()
    IL_004c:  stloc.1
    IL_004d:  ldloca.s   V_1
    IL_004f:  call       instance uint8 [System.Drawing]System.Drawing.Color::get_B()
    IL_0054:  ldc.i4.0
    IL_0055:  ceq
    IL_0057:  br.s       IL_005a

    IL_0059:  ldc.i4.1
    IL_005a:  nop
    IL_005b:  stloc.2
    IL_005c:  ldloc.2
    IL_005d:  brtrue.s   IL_0061

    IL_005f:  nop
    IL_0060:  nop
    IL_0061:  ret
  } // end of method Program::Main