0

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?

3 Answers 3

3

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
}
Sign up to request clarification or add additional context in comments.

1 Comment

Just so you know, Marshal.StructureToPtr also makes a copy of your structure, and does computations to determine how to represent the struct in memory.
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;
    }
}

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.