在 C# 中使用泛型的 StructLayout 属性是否有效?
Does work the StructLayout attribute with generic in C#?
有一段代码使用 StructLayout 属性,泛型如下。
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class Packet<H, Body1, Body2> : IOutlinePacket
where H : new()
where Body1 : IDeviceBody, new()
where Body2 : INetworkBody, new()
{
H Header = new Header();
Body1 DeviceBody = new Body1();
Body2 NetworkBody = new Body2();
}
如果class不是通用的,H,Body1,Body2的顺序将得到保证,并且将按1byte的步长分配。但是我不知道泛型大小写如何。
当然,我知道泛型不支持marshal函数,但我想知道StructLayout情况如何。
我尝试了一些测试来检查这一点,根据测试,它似乎可以工作,但我不知道这是巧合还是一直有效。
对不起,我的英语很糟糕,感谢您的阅读。
这将按预期工作。如果您将指定包装的 StructLayout
添加到通用 class,它将向生成的 IL 添加一个 .pack
指令。
例如,给定这个 class:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class Test<T1, T2> where T1: struct where T2: struct
{
public T1 One;
public T2 Two;
}
它的 IL 输出是这样的:
.class public sequential ansi beforefieldinit Test`2<valuetype .ctor ([System.Runtime]System.ValueType) T1, valuetype .ctor ([System.Runtime]System.ValueType) T2>
extends [System.Runtime]System.Object
{
.pack 1
.size 0
.field public !T1 One
.field public !T2 Two
.method public hidebysig specialname rtspecialname instance void .ctor () cil managed
{
IL_0000: ldarg.0
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
IL_0006: ret
}
}
注意 .pack 1
,它指定了包装。
您可以通过按照以下行编写一些 unsafe
代码来验证此打包是否确实有效:
public static class Program
{
public static void Main()
{
var test = new Test<byte, long>
{
One = 1,
Two = 2
};
unsafe
{
fixed (byte* p1 = &test.One)
fixed (long* p2 = &test.Two)
{
Console.WriteLine((byte*)p2 - p1);
}
}
}
}
使用 Pack = 1
时的输出是 1
。
如果你把packing改成Pack = 4
,输出就是4
.
并且如果将包装更改为Pack = 8
,则输出为8
。
这表明即使不使用编组,也会执行内存中的打包。
There are many packets of a similar format. So I try to create system that can create new packet types combining many other types. for easy to expansion.
我不完全确定你的意思,但可能 "discriminated unions" 将来对你有用 - 但看起来它们不会随时实施很快,所以可能需要几年时间才能使用(如果有的话)。
另请注意,这仅适用于 blittable 类型!
有一段代码使用 StructLayout 属性,泛型如下。
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class Packet<H, Body1, Body2> : IOutlinePacket
where H : new()
where Body1 : IDeviceBody, new()
where Body2 : INetworkBody, new()
{
H Header = new Header();
Body1 DeviceBody = new Body1();
Body2 NetworkBody = new Body2();
}
如果class不是通用的,H,Body1,Body2的顺序将得到保证,并且将按1byte的步长分配。但是我不知道泛型大小写如何。
当然,我知道泛型不支持marshal函数,但我想知道StructLayout情况如何。
我尝试了一些测试来检查这一点,根据测试,它似乎可以工作,但我不知道这是巧合还是一直有效。
对不起,我的英语很糟糕,感谢您的阅读。
这将按预期工作。如果您将指定包装的 StructLayout
添加到通用 class,它将向生成的 IL 添加一个 .pack
指令。
例如,给定这个 class:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class Test<T1, T2> where T1: struct where T2: struct
{
public T1 One;
public T2 Two;
}
它的 IL 输出是这样的:
.class public sequential ansi beforefieldinit Test`2<valuetype .ctor ([System.Runtime]System.ValueType) T1, valuetype .ctor ([System.Runtime]System.ValueType) T2>
extends [System.Runtime]System.Object
{
.pack 1
.size 0
.field public !T1 One
.field public !T2 Two
.method public hidebysig specialname rtspecialname instance void .ctor () cil managed
{
IL_0000: ldarg.0
IL_0001: call instance void [System.Runtime]System.Object::.ctor()
IL_0006: ret
}
}
注意 .pack 1
,它指定了包装。
您可以通过按照以下行编写一些 unsafe
代码来验证此打包是否确实有效:
public static class Program
{
public static void Main()
{
var test = new Test<byte, long>
{
One = 1,
Two = 2
};
unsafe
{
fixed (byte* p1 = &test.One)
fixed (long* p2 = &test.Two)
{
Console.WriteLine((byte*)p2 - p1);
}
}
}
}
使用 Pack = 1
时的输出是 1
。
如果你把packing改成Pack = 4
,输出就是4
.
并且如果将包装更改为Pack = 8
,则输出为8
。
这表明即使不使用编组,也会执行内存中的打包。
There are many packets of a similar format. So I try to create system that can create new packet types combining many other types. for easy to expansion.
我不完全确定你的意思,但可能 "discriminated unions" 将来对你有用 - 但看起来它们不会随时实施很快,所以可能需要几年时间才能使用(如果有的话)。
另请注意,这仅适用于 blittable 类型!