【问题标题】:Marshalling array field in union-like structure在类联合结构中编组数组字段
【发布时间】:2016-07-20 23:25:53
【问题描述】:

我正在尝试使用 byte[] 字段创建类似联合的结构。所以下一个类型声明会导致运行时出错:

    [StructLayout(LayoutKind.Explicit)]
public struct Int64ByteArr
{
    [FieldOffset(0)]
    public UInt64 u64;
    [FieldOffset(0)]
    public Int64 s64;
    [FieldOffset(0), MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]        
    public byte[] bytes;
}

当调用使用该类型变量的函数时,程序会导致具有该描述的异常:

Необработанное исключение типа "System.TypeLoadException" в System.Windows.Forms.dll Дополнительные сведения: Не удалось загрузить тип "Int64ByteArr" из сборки "ChalengeCalc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", так как он содержит поле объекта со смещением 0, которое неверно выровнено или перекрыто полем, не представляющим объект .

翻译成英文:System.Windows.Forms.dll 中“System.TypeLoadException”类型的未处理异常) 附加信息:无法从“ChalengeCalc,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”程序集加载类型“Int64ByteArr”,因为它包含 oaffset 0 的对象字段,该字段与未显示的溢出字段错误对齐一个对象

我也试试这个变种:

    [StructLayout(LayoutKind.Sequential)]
public struct ByteArr8
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
    public byte[] bytes;
    public Byte this[int idx]
    {
        get
        {
            if (idx < 0 || idx > 7) return 0;
            return bytes[idx];
        }
        set
        {
            if (idx < 0 || idx > 7) return;
            bytes[idx] = value;
        }
    }
}
[StructLayout(LayoutKind.Explicit)]
public struct Int64ByteArr
{
    [FieldOffset(0)]
    public UInt64 u64;
    [FieldOffset(0)]
    public Int64 s64;
    [FieldOffset(0)]
    public ByteArr8 bytes;
}

它挂起并出现相同的异常。所以有一个问题:“怎么做?”

【问题讨论】:

  • 您不能将对像 byte[] 这样的引用类型的引用与值类型值重叠。这搞砸了垃圾收集器。您必须改用固定大小的缓冲区。由于数组与 Int64 大小相同,另一个非常简单的解决方法是使用 BitConverter.GetBytes() 读取字节值。

标签: c# marshalling unions


【解决方案1】:

在您的特定情况下,您可以仅编组字节数组字段并为其他字段提供 getter/setter:

[StructLayout(LayoutKind.Sequential)]
struct Int64ByteArr
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
    public byte[] bytes;
    public UInt64 u64
    {
        get { return BitConverter.ToUInt64(bytes, 0); }
        set { bytes = BitConverter.GetBytes(value); }
    }
    public Int64 s64
    {
        get { return BitConverter.ToInt64(bytes, 0); }
        set { bytes = BitConverter.GetBytes(value); }
    }
}

注意:灵感来自 David Heffernan 对 this question 的评论。

我相信,在一般情况下,您必须使用自定义编组。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-23
    • 2012-05-11
    • 1970-01-01
    相关资源
    最近更新 更多