Joel B
Joel B

Reputation: 13140

How to create a variable from a subarray

So I have a gigantic byte-array that represents a data packet. There's various parts of the packet such as a header, message body, stop bits, etc. How can I create variables of the various parts of the array such that when I reference the variable I'm editing the sub-array? I'd like to use the dot notation so that referencing ByteArrayRepresentingPacket.Header would actually reference ByteArrayRepresentingPacket[0], ByteArrayRepresentingPacket.MessageBody would actually reference ByteArrayRepresentingPacket[1] through ByteArrayRepresentingPacket[8], etc. A structure seems suited for this, but how would I translate the structure into a byte-array when I need to pass it?

Upvotes: 0

Views: 697

Answers (3)

Joel B
Joel B

Reputation: 13140

So I ended up going with a structure (like I had hoped I could). Here's the implementation:

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(); }
    }
}

I kept everything as IEnumerableso that I could just use LINQ's .Concat operator (to make everything clean & concise). What I'm unsure of is if the performance savings I gain from using a struct (no boxing/unboxing) will be undone by using IEnumerable Properties and LINQ

Upvotes: 0

Paul Wheeler
Paul Wheeler

Reputation: 20180

You're better off not worrying about forcing your packet structure to be stored as a byte array. The CPU cost of converting to and from a byte array, and the memory costs of the temporary duplicate storage are most likely insignificant. Create a class or set of classes to represent your data structure, and then use BinaryWriter to convert it to a byte array in the format required by your protocol.

If you really want to use a structure, look into the Marshal.StructureToPtr method, and the [LayoutKind] and [MarshalAs] attributes. But be warned, if your data structure contains an variable length fields (strings or arrays), you won't be able to convert it to a byte array using this method. And I don't see any reason why you should go this route. It's really intended for Win32 interop.

EDIT:

Another thought, if you were stuck with a big byte array, and you really wanted to access chunks of it by name, I would create an implementation of IList<T> that took a T[] an offset and a length, and just used the array as its storage. Then you could create a class like so:

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
}

Upvotes: 3

Paula Bean
Paula Bean

Reputation: 458

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;
    }
}

Upvotes: 1

Related Questions