2016-08-25 3 views
0

Я знаю, что передача структур как параметра в метод, возврат их или попытка присвоения значения переменной переменной создает копию всей структуры.Доступ к структурным полям копирует всю структуру?

Теперь посмотрим на гипотетический код ниже:

//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 копируются в ячейку памяти или все регионы [0] трижды?

+0

Это просто проверить с 'ReferenceEquals (Регионы [0] Регионы [0])' – Sehnsucht

+1

Это будет возвращать ложь, потому что копии, которые сделаны при прохождении в качестве параметров метода (регионы [0] будет скопирована дважды). Мой вопрос в том, что копии сделаны даже при простом доступе к членам поля (например, Color и r/g/b в примере). –

ответ

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_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 ора коды. Оба просто передают ссылки.

Итак, вы не Сделайте две копии. Все передается по ссылке.

+0

Он заявил, что 'Foo' не является классом, а структурой. – user3185569

+0

@ user3185569 - Ты прав. Я исправил ответ. – Enigmativity

+0

@ Энигматичность Если внутри оператора if я имел var x = foos [0] .Color.R; то будет скопировано только значение R? –

0

Регион представляет собой массив структур. Я сделал быстрый пример для изучения сгенерированного 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; } 
} 

Как вы можете увидеть в сгенерированном IL ниже get_Color называется 3 раза, и поэтому значение цвета копируется в 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 
+0

Где вы видите значения 'Color', скопированные три раза? – Enigmativity

+0

@Enigmativity 'Foo :: get_Color()' получает копию этого 'Color' AFAIK. – user3185569

+0

@Enigmativity Это имеет большое значение, если «Цвет» является свойством (в моем случае) и публичным полем (как в вашем случае) – user3185569

Смежные вопросы