当前位置:  开发笔记 > 编程语言 > 正文

字节序列化C#中的结构的字节

如何解决《字节序列化C#中的结构的字节》经验,为你挑选了2个好方法。

我正在寻找C#中序列化的语言支持.我可以从ISerializable派生并通过在字节缓冲区中复制成员值来实现序列化.但是,我更喜欢像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 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 frame = new Frame();
            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是此类有效负载的示例.

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



1> JCH2k..:

只需使用以下两种方法:

public static class StructTools
{
    /// 
    /// converts byte[] to struct
    /// 
    public static T RawDeserialize(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;
    }

    /// 
    /// converts a struct to byte[]
    /// 
    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):

[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(byteArray, 0); // 0 is offset in byte[]

和序列化使用

StructTools.RawSerialize(myStruct);



2> Jon Skeet..:

正如Chris所说,您可以使用不安全的代码 - 在这种情况下,您最好确保明确指定布局.当然,你正在降低CLR优化一点的能力 - 你最终会得到不对齐的访问,失去原子性等等.这可能与你无关,但值得记住.

就个人而言,我认为这是一个非常脆弱的序列化/反序列化方式.如果有任何变化,您的数据将无法读取.如果您尝试在使用不同字节序的体系结构上运行,您将发现所有值都被搞砸了.此外,只要您需要使用引用类型,使用内存中布局就会失败 - 这很可能影响你自己的类型设计,鼓励你使用结构,否则你会使用类.

我更喜欢显式读取和写入值(例如,使用BinaryWriter,或者最好使用允许您设置字节序的二进制写入器版本)或使用协议缓冲区等可移植序列化框架.

推荐阅读
mobiledu2402851203
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有