Meh
Meh

Reputation: 7166

How to convert an array of value struct to bytes?

I have a System.Array of value struct types, something like this:

public value struct Position
{
    int timestamp;
    float x;
    float y;
}

Position[] positions = new Position[1000 * 1000];

After I initialize the array with values, how can I get a byte[] of it's content, without serializing one item at a time?

In C++/CLI I would use a pin_ptr to get the pointer to the array content and I would copy the data from there. Can I do something like this in C#?

EDIT: I need to write the raw data to disk, as if it were a C struct, without any kind of serialization.

I tagged this question as C# for broader exposure, but actually I'm trying to serialize the data from IronPython, so this means I can't use any unsafe C# functionality.

Upvotes: 2

Views: 880

Answers (3)

Andy Wilson
Andy Wilson

Reputation: 1383

Here's a method that doesn't require unsafe code:

[Updated to remove the for loop and perform the copy in a single pass]

private static byte[] StructureToByteArray(Position[] posArray)
{
    if (posArray == null || posArray.Length == 0)
    {
        return new byte[0];
    }

    var lenOfObject = Marshal.SizeOf(typeof(Position));
    var len = lenOfObject * posArray.Length;
    var arr = new byte[len];

    var handle = GCHandle.Alloc(posArray, GCHandleType.Pinned);
    try
    {
        var ptr = handle.AddrOfPinnedObject();
        Marshal.Copy(ptr, arr, 0, len);
    }
    finally
    {
        handle.Free();
    }

    return arr;
}

Upvotes: 1

Dan Bryant
Dan Bryant

Reputation: 27495

I believe this is the equivalent to the C++/CLI pin_ptr using unsafe C# code:

    public static unsafe byte[] GetBytes(Position[] positions)
    {
        byte[] result = new byte[positions.Length * Marshal.SizeOf(typeof(Position))];
        fixed (Position* ptr = &positions[0])
        {
            Marshal.Copy((IntPtr)ptr, result, 0, result.Length);
        }
        return result;
    }

Upvotes: 1

Arion
Arion

Reputation: 31239

Maybe this will help:

[Serializable()]
    public struct Position
    {
        int timestamp;
        float x;
        float y;
    }


    static void Main(string[] args)
    {
        var positions = new Position[1000 * 1000];
        GetBytes(positions);
    }
    private static byte[] GetBytes(object obj)
    {
        using (var memoryStream = new System.IO.MemoryStream())
        {
            var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            binaryFormatter.Serialize(memoryStream, obj);
            return memoryStream.ToArray();
        }
    }

Upvotes: 2

Related Questions