C#中结构的字节序列化字节 [英] Byte for byte serialization of a struct in C#

查看:25
本文介绍了C#中结构的字节序列化字节的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找 C# 中序列化的语言支持.我可以从 ISerializable 派生并通过复制字节缓冲区中的成员值来实现序列化.但是,我更喜欢一种更自动化的方式,就像在 C/C++ 中可以做到的那样.

I'm looking for language support of serialization in C#. I could derive from ISerializable and implement the serialization by copying member values in a byte buffer. However, I would prefer a more automatic way like one could do in C/C++.

考虑以下代码:

using System;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace XBeeHelper
{
    class XBee
    {
        [Serializable()]
        public struct Frame<FrameType> where FrameType : struct
        {
            public Byte StartDelimiter;
            public UInt16 Lenght;
            public Byte APIIdentifier;
            public FrameType FrameData;
            public Byte Checksum;
        }

        [Serializable()]
        public struct ModemStatus
        {
            public Byte Status;
        }

        public Byte[] TestSerialization()
        {
            Frame<ModemStatus> frame = new Frame<ModemStatus>();
            frame.StartDelimiter = 1;
            frame.Lenght = 2;
            frame.APIIdentifier = 3;
            frame.FrameData.Status = 4;
            frame.Checksum = 5;

            BinaryFormatter formatter = new BinaryFormatter();
            MemoryStream stream = new MemoryStream();
            formatter.Serialize(stream, frame);
            Byte[] buffer = stream.ToArray();
            return buffer;
        }
    }
}

我有一个通用的 Frame 结构,它充当多种类型的有效载荷的包装器,用于串行传输.ModemStatus 就是此类负载的一个示例.

I have a generic Frame struct acting as a wrapper for many types of payload, for serial transmission. ModemStatus is an example of such payload.

但是,运行 TestSerialization() 会返回一个 382 字节长的缓冲区(没有预期的内容)!它应该包含 6 个字节.是否可以在不手动序列化的情况下正确序列化这些数据?

However, running TestSerialization() returns a buffer 382 bytes long (without the expected content)! It should have contained 6 bytes. Is it possible to serialize this data correctly without manual serializing?

推荐答案

就用这两个方法:

public static class StructTools
{
    /// <summary>
    /// converts byte[] to struct
    /// </summary>
    public static T RawDeserialize<T>(byte[] rawData, int position)
    {
        int rawsize = Marshal.SizeOf(typeof(T));
        if (rawsize > rawData.Length - position)
            throw new ArgumentException("Not enough data to fill struct. Array length from position: "+(rawData.Length-position) + ", Struct length: "+rawsize);
        IntPtr buffer = Marshal.AllocHGlobal(rawsize);
        Marshal.Copy(rawData, position, buffer, rawsize);
        T retobj = (T)Marshal.PtrToStructure(buffer, typeof(T));
        Marshal.FreeHGlobal(buffer);
        return retobj;
    }

    /// <summary>
    /// converts a struct to byte[]
    /// </summary>
    public static byte[] RawSerialize(object anything)
    {
        int rawSize = Marshal.SizeOf(anything);
        IntPtr buffer = Marshal.AllocHGlobal(rawSize);
        Marshal.StructureToPtr(anything, buffer, false);
        byte[] rawDatas = new byte[rawSize];
        Marshal.Copy(buffer, rawDatas, 0, rawSize);
        Marshal.FreeHGlobal(buffer);
        return rawDatas;
    }
}

并像这样指定您的结构(指定确切的大小并按一个字节打包(对齐).默认为 8):

And specify your struct like this (Specify the exact size and pack (align) by one byte. default is 8):

[StructLayout(LayoutKind.Explicit, Size = 11, Pack = 1)]
private struct MyStructType
{
    [FieldOffset(0)]
    public UInt16 Type;
    [FieldOffset(2)]
    public Byte DeviceNumber;
    [FieldOffset(3)]
    public UInt32 TableVersion;
    [FieldOffset(7)]
    public UInt32 SerialNumber;
}

现在您可以使用

StructTools.RawDeserialize<MyStructType>(byteArray, 0); // 0 is offset in byte[]

并使用

StructTools.RawSerialize(myStruct);

这篇关于C#中结构的字节序列化字节的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆