C#学习汇总 - 总目录


可直接查看MSDN文档,讲解很清晰
https://learn.microsoft.com/zh-cn/dotnet/api/system.runtime.interopservices.structlayoutattribute?view=net-6.0

一、定义:

在这里插入图片描述

二、说明:

应用场景:可以将此特性应用于类或结构。

公共语言运行时控制托管内存中类或结构的数据字段的物理布局。

但是,如果要将类型传递给非托管代码,则可以使用 StructLayoutAttribute 特性来控制类型的非托管布局。

  • LayoutKind.Sequential 强制成员按其出现的顺序进行排列
    【下边内容没理解???】
    对于直接类型的类型,会 LayoutKind.Sequential 在托管内存和非托管内存中控制布局。
    对于不可直接复制的类型,它会在将类或结构封送到非托管代码时控制布局,但不会控制托管内存中的布局。

  • 使用特性 LayoutKind.Explicit 来控制每个数据成员的精确位置
    这会影响托管和非托管布局,同时用于本机和非直接复制类型。
    使用 LayoutKind.Explicit 需要使用 FieldOffsetAttribute 属性来指示每个字段在类型中的位置

默认情况下,c #、Visual Basic 和 c + + 编译器将 Sequential 布局值应用到结构
对于类,必须 LayoutKind.Sequential 显式应用值

在这里插入图片描述在这里插入图片描述

在这里插入图片描述

字段Pack:【如何理解与应用???】
Pack定义了结构的封装大小。可以是1、2、4、8、16、32、64、128或特殊值0。特殊值0表示当前操作平台默认的压缩大小。

三、示例:【要理解!】

下面的示例演示函数的托管声明 GetSystemTime ,并定义 MySystemTime 带有布局的类 LayoutKind.Explicit 。 GetSystemTime 获取系统时间,并将其打印到控制台。

using System;
using System.Runtime.InteropServices;

namespace InteropSample
{

    [StructLayout(LayoutKind.Explicit, Size = 16, CharSet = CharSet.Ansi)]
    public class MySystemTime
    {
        [FieldOffset(0)] public ushort wYear;
        [FieldOffset(2)] public ushort wMonth;
        [FieldOffset(4)] public ushort wDayOfWeek;
        [FieldOffset(6)] public ushort wDay;
        [FieldOffset(8)] public ushort wHour;
        [FieldOffset(10)] public ushort wMinute;
        [FieldOffset(12)] public ushort wSecond;
        [FieldOffset(14)] public ushort wMilliseconds;
    }

    internal static class NativeMethods
    {
        [DllImport("kernel32.dll")]
        internal static extern void GetSystemTime([MarshalAs(UnmanagedType.LPStruct)] MySystemTime st);
    };

    class TestApplication
    {
        public static void Main()
        {
            try
            {
                MySystemTime sysTime = new MySystemTime();
                NativeMethods.GetSystemTime(sysTime);
                Console.WriteLine("The System time is {0}/{1}/{2} {3}:{4}:{5}", sysTime.wDay,
                   sysTime.wMonth, sysTime.wYear, sysTime.wHour, sysTime.wMinute, sysTime.wSecond);
            }
            catch (TypeLoadException e)
            {
                Console.WriteLine("TypeLoadException : " + e.Message);
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception : " + e.Message);
            }

            Console.ReadLine();
        }
    }
}

运行结果:【运行时间是UTC,北京时间是:UTC+8】
在这里插入图片描述

在这里插入图片描述

四、补充

结构体是由若干成员组成的.布局有两种

1.Sequential,顺序布局

struct S1
{
  int a;
  int b;
}

那么默认情况下在内存里是先排a,再排b
也就是如果能取到a的地址,和b的地址,则相差一个int类型的长度,4字节

[StructLayout(LayoutKind.Sequential)] 
struct S1
{
  int a;
  int b;
}

这样和上一个是一样的.因为默认的内存排列(struct,class需要显式指出)就是Sequential,也就是按成员的先后顺序排列。

2.Explicit,精确布局

需要用FieldOffset()设置每个成员的位置,这样就可以实现类似C语言的公用体的功能。

[StructLayout(LayoutKind.Explicit)] 
struct S1
{
  [FieldOffset(0)]
  int a;
  [FieldOffset(0)]
  int b;
}

这样a和b在内存中地址相同。

C#学习汇总 - 总目录

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐