4

I have a dictionary in c#

private Dictionary<int, UserSessionInfo> userSessionLookupTable = new Dictionary<int, UserSessionInfo>();

Now I have created a dictionary object

this.userSessionLookupTable.Add(userSessionInfoLogin.SessionId, userSessionInfoLogin);

Now I want a generic method to serialize and de-serialize the dictionory to byte array. Like

public static void Serialize(Dictionary<int, object> dictionary, Stream stream)
{
 //Code here
}

and

public static static Dictionary<int, object> Deserialize(Stream stream)
{
 //Code here
}

Can anyone help me on this??

Visual Vincent
  • 18,045
  • 5
  • 28
  • 75
S M
  • 3,133
  • 5
  • 30
  • 59

5 Answers5

8

Try this....

    public static void Serialize<Object>(Object dictionary, Stream stream)
    {
        try // try to serialize the collection to a file
        {
            using (stream)
            {
                // create BinaryFormatter
                BinaryFormatter bin = new BinaryFormatter();
                // serialize the collection (EmployeeList1) to file (stream)
                bin.Serialize(stream, dictionary);
            }
        }
        catch (IOException)
        {
        }
    }

    public static Object Deserialize<Object>(Stream stream) where Object : new()
    {
        Object ret = CreateInstance<Object>();
        try
        {
            using (stream)
            {
                // create BinaryFormatter
                BinaryFormatter bin = new BinaryFormatter();
                // deserialize the collection (Employee) from file (stream)
                ret = (Object)bin.Deserialize(stream);
            }
        }
        catch (IOException)
        {
        }
        return ret;
    }
    // function to create instance of T
    public static Object CreateInstance<Object>() where Object : new()
    {
        return (Object)Activator.CreateInstance(typeof(Object));
    }

Usage...

        Serialize(userSessionLookupTable, File.Open("data.bin", FileMode.Create));
        Dictionary<int, UserSessionInfo> deserializeObject = Deserialize<Dictionary<int, UserSessionInfo>>(File.Open("data.bin", FileMode.Open));

I have used 'Object' in the code above to fulfil your requirements but personally I would use 'T' which usually denotes a generic object in C#

Monty
  • 1,534
  • 2
  • 10
  • 12
3

A bit late to answer maybe but here is a practical and more general answer from my experience: Use simple JSON serialisation if you want something quick and easy or if there is not much demand for data size or performance. If you want something highly space efficient, fast and cross-platform as well, use Google Protocol Buffers.

JSON

string output = JsonConvert.SerializeObject(myObject);
var copyOfMyObject = JsonConvert.DeserializeObject<MyObject>(output);

There are a lot of ways you can control the serialisation and use streams and so on.

Json.Net also supports dictionaries too.

Protobuf

There are two ways of using protobuf in c#: Using .proto message definitions and generate code or reflection based approach using your class definitions and attributes. It depends on your project but I prefer the message definitions personally.

Note that you might have to do your own munging before and after serialisation and deserialisation to use with a Dictionary.

Message definition based: using proto3

.proto file:

message Person {
  int32 id = 1;
  string name = 2;
}

Generate code using Google Protobuf:

protoc --csharp_out=$DST_DIR $SRC_DIR/person.proto

Serialise / deserialise using generated classes:

Person john = ...;
john.WriteTo(stream);
var copyOfJohn = Person.Parser.ParseFrom(stream);

Also, a quick note to let you know that there is probably a less known feature of proto3 is the capability of using JSON.

Reflection based: Protobuf-net

Here is a quick example (copied from protobuf-net page)

[ProtoContract]
class Person {
    [ProtoMember(1)]
    public int Id {get;set;}
    [ProtoMember(2)]
    public string Name {get;set;}
}
Serializer.Serialize(file, person);
newPerson = Serializer.Deserialize<Person>(file);

Binary, text, streams, oh my!

Apologies, I sort of ignored the question about 'Binary' serialisation (and was not a specific BinaryFormatter question) since there are lots of ways you can use streams to deal with data flowing in and out of a process. C# stream, reader and writer and other System.IO APIs are quite well documented.

mtmk
  • 6,176
  • 27
  • 32
2

You could use a MemoryStream for this purpose unless you don't want to create a file. But for the serializing method, if you don't want to return a value you should probably mark the stream parameter as [Out].

public static void Serialize(Dictionary<int, object> dictionary, [Out] Stream stream)
{
    stream = new MemoryStream();
    new BinaryFormatter().Serialize(stream, dictionary);
}

public static Dictionary<int, object> Deserialize(Stream stream)
{
    return (Dictionary<int, object>)new BinaryFormatter().Deserialize(stream);
}

This will perform binary serialization.

EDIT:

To get it as a byte array you can just cast the stream returned from the Serialize() method to a MemoryStream, and then call .ToArray() on it.

This is an example:

MemoryStream outputStream;
Serialize(your dictionary here, outputStream);
byte[] bytes = outputStream.ToArray();
Kaique Santos
  • 49
  • 1
  • 5
Visual Vincent
  • 18,045
  • 5
  • 28
  • 75
  • you should mark the stream as out if you are just going to create a new one – MikeT Mar 31 '16 at 12:50
  • @MikeT : Thanks, I was unsure which one of `ref` or `Out` I should've used. – Visual Vincent Mar 31 '16 at 12:52
  • 1
    ref means you are passing the objects reference not its value, this means that changes to the object are reflected in the passing member (note classes are reference types so are always ref), out means that you are going to create a object and return it from the method replacing any value that was initially inside it in the calling function – MikeT Mar 31 '16 at 12:57
  • I'm not a native C# developer, but I know what `ref` does (equivalent `ByRef` in Visual Basic). You wrote a simple and clear explanation for it though ;). I use `ref` sometimes instead of `Out` to save memory (this is just for special cases though). – Visual Vincent Mar 31 '16 at 13:01
1

For Binary Serialization

For more info take a look at BinaryFormatter.

Here is a possible solution:

public void Serialize(Dictionary<int, UserSessionInfo> dictionary, Stream stream)
{
    BinaryWriter writer = new BinaryWriter(stream);
    writer.Write(dictionary.Count);
    foreach (var obj in dictionary)
    {
        writer.Write(obj.Key);
        writer.Write(obj.Value);
    }
    writer.Flush();
}

public Dictionary<int, UserSessionInfo> Deserialize(Stream stream)
{
    BinaryReader reader = new BinaryReader(stream);
    int count = reader.ReadInt32();
    var dictionary = new Dictionary<int, UserSessionInfo>(count);
    for (int n = 0; n < count; n++)
    {
        var key = reader.ReadInt32();
        var value = reader.ReadString();
        dictionary.Add(key, value);
    }
    return dictionary;                
}

but you still need to have UserSessionInfo ToString() converter;


For XML Serialization

Create a sample class Session

public class Session
{
    [XmlAttribute]
    public int SessionID;
    [XmlAttribute]
    public UserSessionInfo SessionInfo;
}

Then you can create XmlSerializer if you want to serialize it as XML

XmlSerializer serializer = new XmlSerializer(
    typeof(Session[]),
    new XmlRootAttribute() { ElementName = "sessions" }
);

And now you can serialize or deserialize.

Serialization:

serializer.Serialize(
    stream, 
    dict.Select(kv => new Session(){SessionID = kv.Key, SessionInfo = kv.Info}).ToArray()
);

Deserialization:

var deserialized = (
    (Session[])serializer.Deserialize(stream)
).ToDictionary(i => i.id, i => i.info);

But you need to have ToString() method in your UserSessionInfo to store it in the XML.

And the XML may look like this:

<sessions>
    <session id='int_goes_here' value='string_goes_here'/>
</sessions>

Hope this helps.

Markiian Benovskyi
  • 2,137
  • 22
  • 29
0

unless you want to build your own completely custom serializer then you need to use the built in serialization structure

The dictionary and all the referenced types must implement the inbuilt serialisation structure which requires classes to be decorated witht the correct attributes ie [Serializable], or [DataContact] and as object can't implement it then you can't serialise it directly, you need to change it to a serializable type

MikeT
  • 5,398
  • 3
  • 27
  • 43
  • Note that using attributes is not usually called Implementing, and there does exist an ISerializable interface (https://msdn.microsoft.com/en-us/library/system.runtime.serialization.iserializable(v=vs.110).aspx) – David Mar 31 '16 at 12:39
  • your quick off the mark, i realised i need to correct the terminology but was locked out by you editing it – MikeT Mar 31 '16 at 12:43