我知道将结构作为参数传递给方法,返回它们,或者尝试将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]三次?
答案 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
您会注意到ldelema
和ldflda
操作码的两个批次。两者都只是传递参考文献。
所以,你不制作两份副本。一切都通过参考传递。
答案 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