如何从子数组创建变量

时间:2010-12-22 18:28:23

标签: c# c#-3.0 aliasing arrays

所以我有一个代表数据包的巨大字节数组。包的各个部分,如标题,消息体,停止位等。如何创建数组各个部分的变量,以便在我引用变量时我正在编辑子数组?我想使用点符号,以便引用ByteArrayRepresentingPacket.Header实际引用ByteArrayRepresentingPacket[0]ByteArrayRepresentingPacket.MessageBody实际引用ByteArrayRepresentingPacket[1]ByteArrayRepresentingPacket[8]等。结构看起来很适合这个,但是当我需要传递它时,如何将结构转换为字节数组呢?

3 个答案:

答案 0 :(得分:3)

最好不要担心强制将数据包结构存储为字节数组。转换到字节数组和从字节数组转换的CPU成本以及临时重复存储的内存成本很可能是微不足道的。创建一个或一组类来表示您的数据结构,然后使用BinaryWriter将其转换为协议所需格式的字节数组。

如果您确实想要使用结构,请查看Marshal.StructureToPtr方法以及[LayoutKind][MarshalAs]属性。但请注意,如果您的数据结构包含可变长度字段(字符串或数组),则无法使用此方法将其转换为字节数组。而且我认为你不应该走这条路。它真的适用于Win32互操作。

修改

另一个想法,如果你遇到一个大字节数组,并且你真的想按名称访问它的块,我会创建一个IList<T>的实现,它带有T[]个偏移量一个长度,只是使用数组作为其存储。然后你可以像这样创建一个类:

public class Packet
{
    public byte[] PacketData;
    public SubArray<byte> Header;
    public SubArray<byte> MessageBody;
    // Add more SubArrays for each of the remainder of your 8 packet pieces

    //modify this constructor as needed
    public Packet(byte[] data)
    {
        // replace the offsets and lengths here with appropriate data
        Header = new SubArray<byte>(data, 0, 10);
        MessageBody = new SubArray<byte>(data, 10, 100);
    }
}

public class SubArray<T> : IList<T>
{
    private T[] data;
    private int offset;
    private int length;

    public SubArray(T[] data, int offset, int length)
    {
         this.data = data;
         this.offset = offset;
         this.length = length;
    }

    public T this[int i]
    {
         get
         {
             if (i < 0 || i >= length) throw new ArgumentOutOfRangeException();
             return data[i + offset];
         }

         set
         {
             if (i < 0 || i >= length) throw new ArgumentOutOfRangeException();
             data[i + offset] = value;
         }
    }

    // TODO: Implement the rest of IList<T> accordingly
}

答案 1 :(得分:1)

public class Packet
{
    public byte[] Header;
    public byte[] MessageBody;
    // Add a single-dimensional byte array for each of the remainder of your 8 packet //pieces

    //modify this constructor as needed
    public Packet(byte[] header, byte[] messageBody[])
    {
        Header = header;
        MessageBody = messageBody;
    }

    public byte[][] ToArray()
    {
        byte[][] byteArray = new byte[8][];
        byteArray[0] = Header;
        byteArray[1] = MessageBody;
        // The rest of your 8 go here
        return byteArray;
    }
}

答案 2 :(得分:0)

所以我最终选择了一个结构(就像我希望的那样)。这是实施:

public struct Packet
{
    /// <summary>
    /// Constructor for initializing packet
    /// </summary>
    /// <param name="header"></param>
    /// <param name="message"></param>
    public Packet(byte[] header, byte[] message)
        : this()
    {
        this.Header = header;
        this.Message = message;
    }

    // Properties representing each part of the sub-packet parts (can be made private if needed)
    public IEnumerable<byte> Header { get; set; }
    public IEnumerable<byte> Message { get; set; }
    public IEnumerable<byte> StopBit { get { return new byte[1] { 0xFF }; } }

    /// <summary>
    /// Returns the byte representation of the whole packet
    /// </summary>
    public byte[] GetBytes
    {
        get { return Header.Concat(Message).Concat(StopBit).ToArray(); }
    }
}

我将所有内容保留为IEnumerable,以便我可以使用LINQ的.Concat运算符(使所有内容变得干净简洁)。我不确定的是,通过使用IEnumerable属性和LINQ

,可以通过使用结构(无装箱/拆箱)获得的性能节省。