实际上,与相关阵列插槽关联的内存由值填充。给你的代码一个小例子显示了什么发生。请在线查看评论。这是为了发布版本。
static void Main(string[] args)
{
Foo[] foos = new Foo[10];
foos[1] = new Foo(127, 255);
Console.ReadLine();
}
上述代码被JIT编译如下
// Method setup
00280050 55 push ebp
00280051 8bec mov ebp,esp
00280053 56 push esi
// Create instance of Foo[]
00280054 b98a141d00 mov ecx,1D148Ah
00280059 ba0a000000 mov edx,0Ah
0028005e e8b121f4ff call CORINFO_HELP_NEWARR_1_VC (001c2214)
00280063 8bd0 mov edx,eax
// Array range check
00280065 837a0401 cmp dword ptr [edx+4],1
00280069 7624 jbe
// Assign foos[1] = new Foo(127, 255)
0028006b 8d4210 lea eax,[edx+10h] <-- load location of foos[1] in eax
0028006e ba7f000000 mov edx,7Fh <-- load 127 in edx
00280073 beff000000 mov esi,0FFh <-- load 255 in esi
00280078 8910 mov dword ptr [eax],edx <-- move the value 127 to foos[1]
0028007a 897004 mov dword ptr [eax+4],esi <-- move the value 255 to foos[1] + offset
// This is just for the Console.ReadLine() part + rest of Main
0028007d e8d2436305 call mscorlib_ni!System.Console.get_In() (058b4454)
00280082 8bc8 mov ecx,eax
00280084 8b01 mov eax,dword ptr [ecx]
00280086 8b402c mov eax,dword ptr [eax+2Ch]
00280089 ff501c call dword ptr [eax+1Ch]
// Epilog
0028008c 5e pop esi
0028008d 5d pop ebp
0028008e c3 ret
//Exception handling
0028008f e8f05e7f70 call clr!JIT_RngChkFail (70a75f84)
00280094 cc int 3
总之
所以,代码加载在寄存器中的常数,然后这些寄存器与的相关部分相关联的存储器的值复制数组实例。
据我记得,是的。结构是值类型,所以不是覆盖foos [i]的引用(就像你看到的类),而是覆盖整个结构在数组中的那个位置。垃圾收集器不必清理结构,因为它被物理覆盖。为了测试,当Foo被声明为'struct'并且当它被声明为'class'时,计算Foo数组的大小,理论上,大小应该是'nElements * IntPtr.Size'类和nElements * sizeof(Foo)'为结构体;但我从来没有在C#中试过,所以我可能是错的。 – 2012-07-06 02:11:09
我希望你能以某种方式使它成为'new'直接覆盖Foo对象,而不是创建并复制。 – SimpleVar 2012-07-06 02:13:14
@Yorye我认为它会和声明long i = 1 + 2一样;值3从表达式(1 + 2)创建,然后复制到i中。所以真的,它与C风格语言通常的表现没有什么不同。 – CodeFusionMobile 2012-07-06 02:18:33