十四:CLR如何控制类型字段的布局

     CLR能按照它所选择的任何方式来排列类型的字段,可以指示是保持开发人员指定的顺序还是根据需要来重新排列,其目的是为了提高性能。

     在定义类或结构上应用System.Runtime.InteropServices.StructLayoutAttribute属性来指定CLR使用何种方式来排列。

     LayoutKind.Auto:CLR自动排列字段

     LayoutKind.Sequential:开发人员排列的字段

     LayoutKind.Explicit:使用偏移量在内存中显示的排列字段的顺序

     如果我们不指定它的属性,编译器会选择它默认的属性。

     C#编译器为引用类型选择LayoutKind.Auto为它的默认属性,为值类型选择LayoutKind.Sequential,因为结构会经常用于与非托管代码进行互操作,字段必须保持开发人员定义的顺序,但如果创建的值类型不会与非托管代码互操作,则应该覆盖C#编译器的默认设定。如下:

using System;

using System.Runtime.InteropServices;

//该结构不与非托管代码互操作,所以覆盖C#编译器的默认属性,让它为自动排列,提高性能

[StructLayout(LayoutKind.Auto)]

internal struct SomeValType

{

    Byte b;

    Int32 x;

}

     StructLayoutAttribute还允许我们显式指定每个字段的偏移量,这要求向其构造器传递LayoutKind.Explicit,然后向每个字段应用System.Runtime.InteropServices.FieldOffsetAttribute属性的一个实例,并向这个属性构造器传入一个Int32的值,指出字段第一个字节距离实例起始处的偏移量(以字节为单位),显式布局通常用于非托管中的一个union(联合行为),因为可能有多个字段起始于内存中的一个偏移位置。Unino是一种特殊的类,一个union中的数据成员在内存中的存储是互相重叠的,每个数据成员都从相同的内存地址开始,分配给union的存储区数量是“要包含它最大的数据成员”所需的内存数。同一时刻只有一个成员可以被赋给一下值。如下:

using System;

using System.Runtime.InteropServices;

//开发人员显示的排列这个值类型的字段

[StructLayout(LayoutKind.Explicit)]

internal struct SomeValType

{

    [FieldOffset(0)]

    Byte b;

    [FieldOffset(0)]

    Int32 x;        //b和x字段在这个类型的实例中相互重叠

}

     在一个类型中,一个引用类型和一个值类型相互重叠是非法的。在一个类型中,虽然允许多个引用类型在同一个起始偏移位置处相互重叠,但这是无法验证的。如果定义一个类型,并让其中的多个值类型相互重叠,则是合法的,但重叠的字段必须是公共的,如果一个公共的,一个是私有的,则无法通过验证。

 

 

posted @ 2009-01-27 19:28  Done  阅读(426)  评论(0编辑  收藏  举报