在 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 类型!

See here for the documentation