2

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.

6
  • 1
    Doesn't the Convert.GetBytes() work? Commented Dec 15, 2011 at 16:28
  • Duplicate: stackoverflow.com/questions/1068541/… Commented Dec 15, 2011 at 16:29
  • @Default: if you are referring to BitConverter.GetBytes, no, it doesn't work. It returns a byte[] with a single byte inside Commented Dec 15, 2011 at 16:34
  • 1
    What are you trying to do with the resultant byte array? Do you need to store it in a DB, send to a web service, or ??? Knowing this might help us come up with the appropriate solution. Commented Dec 15, 2011 at 16:50
  • Is your code/application the only thing that will be reading that data from disk? I.e. do you have to follow an agreed upon format, or can it be any format? If it can be any format, I would use binary serialization, since it's easy to use. Commented Dec 15, 2011 at 17:08

3 Answers 3

2

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

3 Comments

I don't think that the Serialization formatters return the raw data.
This approach does give a byte array, and it requires very little coding effort, so I think this is perfectly valid answer. Granted, the resulting byte array will not be as small as possible, because it does contain some type information that is used for deserialization. It's up to the individual to decide whether this suits their need.
I just think that using a standard package i C# is better then using unsafe code. I also think it is true that when serializing the object it has to save the type information. So the byte array might be larger but the a standard solution is I think is more preferable
1

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

3 Comments

Same question as on the unsafe answer: Would it be a good idea to apply the StructLayout attribute with a LayoutKind of either Sequential or Explicit to the Position struct if using this approach, or does it not matter?
It would be a good idea to specify LayoutKind.Sequential. Since structs are so often used for interop, it's the default for the C#/VB.NET compilers (and probably others), but there's no guarantee that will remain true.
This goes through each item. I want to avoid that.
1

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

3 Comments

Is it necessary to apply the StructLayout attribute with a LayoutKind of either Sequential or Explicit to the Position struct in order to reliably use this approach? Just wondering.
Thanks, but I can't use unsafe. I've updated the description with why.
@Dr. Wily's Apprentice, I would definitely recommend using Explicit layout if you're going to try to interoperate with unmanaged code that's expecting a specific binary layout. I'm not sure how strong the guarantees are for automatic layout positioning.

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.