C#【高级篇】StructLayout特性是什么?怎么用?
C#【高级篇】StructLayout特性是什么?怎么用?
C#【高级篇】StructLayout特性是什么?怎么用?
可直接查看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在内存中地址相同。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)