views:

188

answers:

4

In C# how can I serialize a List<int> to a byte[] in order to store it in a DB field?

I know how to serialize to a file on the disk, but how do I just serialize to a variable?

Here is how I serialized to the disk:

            List<int> l = IenumerableofInts.ToList();
            Stream s = File.OpenWrite("file.bin");
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(s, lR);
            s.Close();

I'm sure it's much the same but I just can't wrap my head around it.

+8  A: 

Use a MemoryStream instead of the file stream:

Stream s = new MemoryStream();

This will place the data in the s variable, which you can read later on in your application.

In order to read from it, you will need to set the Position to 0, so seeking will start from the beginning of the stream (if reading in chunks), or use ToArray() on it to retrieve the complete content.

Oded
For someone new to MemoryStream it's important to also point out that you'll have to set the Position back to 0 before reading from it. That's often overlooked and causes new devs some head scratching.
Sam
@Sam - thanks for the comment. Answer updated with this info.
Oded
@Sam. Incorrect. You can use the `.ToArray()` method to get the contents of the MemoryStream regardless of position.
Jason Punyon
@Jason Punyon, `.ToArray()` will copy the data to a new array whereas setting the `.Position` to zero gives you access to the underlying data directly without an extra copy.
Sam
@Sam: Agreed. I'd think it'd just be easier to get the Array representation (that's what the Q is about) of the bytes and dispose of the stream immediately.
Jason Punyon
A: 

Use a generic serializer

private static string SerializeObject<T>(T source)
{
    var serializer = new XmlSerializer(typeof(T));

    using (var sw = new System.IO.StringWriter())
    using (var writer = new XmlTextWriter(sw))
    {
        serializer.Serialize(writer, source);
        return sw.ToString();
    }
}

http://weblogs.asp.net/rajbk/archive/2009/10/04/xmlserializer-and-invalid-xml.aspx

Raj Kaimal
He wants a byte array, not a string.
Jason Punyon
@Jason - on the wire, there isn't a vast amount between them.
Marc Gravell
@Marc Gravell: I won't wrestle with the master over serialization, but even for a list of an object that has a goodly number of verbosely named properties?
Jason Punyon
@Jason - oh, absolutely *xml* is overkill - heck, tsv / csv etc would be easier. My point was simply that there is little fundamental difference between strings and bytes. One is largely a subset of the other, obviously, but you know what I mean.
Marc Gravell
+3  A: 

To put it bluntly: I would put them in another table in the database that has a one-to-many foreign-key relationship with its parent record.

That way, you can do normal DB operations with them, like retrieving parent records based on which ints are in the child table.

R. Bemrose
+1. Even if you serialize it to XML and store it as an XML column type (in SQL Server), you're still better off for searching/retrieval/reporting than if you use binary serialization. And normalized tables are generally a better choice than that.
TrueWill
+1  A: 

Personally, I would not use BinaryFormatter for this purpose - it is implementation specific and overly expensive. I would be tempted to (one of):

1: use BinaryWriter / BinaryReader to do it manually (but note that this is easy to interpret from any API):

    // note I've used arrays in the example; lists are identical
    int[] data = { 1, 2, 3, 4, 5 };
    byte[] raw;
    using (var ms = new MemoryStream())
    using (var writer = new BinaryWriter(ms))
    {
        writer.Write(data.Length);
        foreach(int i in data) {
            writer.Write(i);
        }
        writer.Close();
        raw = ms.ToArray();
    }
    // read it back
    using (var ms = new MemoryStream(raw))
    using (var reader = new BinaryReader(ms))
    {
        int count = reader.ReadInt32();
        data = new int[count];
        for (int i = 0; i < count; i++)
        {
            data[i] = reader.ReadInt32();
        }
    }

or 2: use an implemenation-independent serialization format, such as protobuf; here I'm using protobuf-net

    int[] data = { 1, 2, 3, 4, 5 };
    byte[] raw;
    using (var ms = new MemoryStream()) {
        Serializer.Serialize(ms, data);
        raw = ms.ToArray();
    }
    // read it back
    using (var ms = new MemoryStream(raw)) {
        data = Serializer.Deserialize<int[]>(ms);
    }

Note that (1) uses 24 bytes for the example (6 * 4 bytes); (2) uses 10 bytes (in part because the numbers are simple, but actually protobuf has some tricks (such as "packed" data) that we aren't even using here).

Marc Gravell