Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic Object Serialization

Tags:

I tried to serialize a DynamicObject class with BinaryFormatter, but:

  • Output file is too big, not exactly wire-friendly
  • Circular References not handled (stuck while serializing)

Since serializing a DynamicObject means very little by itself, here's the class I tried to serialize:

[Serializable()] class Entity     : DynamicObject, ISerializable {      IDictionary<string, object> values = new Dictionary<string, object>();      public Entity()     {      }      protected Entity(SerializationInfo info, StreamingContext ctx)     {         string fieldName = string.Empty;         object fieldValue = null;          foreach (var field in info)         {             fieldName = field.Name;             fieldValue = field.Value;              if (string.IsNullOrWhiteSpace(fieldName))                 continue;              if (fieldValue == null)                 continue;              this.values.Add(fieldName, fieldValue);         }      }      public override bool TryGetMember(GetMemberBinder binder, out object result)     {         this.values.TryGetValue(binder.Name, out result);          return true;     }      public override bool TrySetMember(SetMemberBinder binder, object value)     {         this.values[binder.Name] = value;          return true;     }              void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)     {                     foreach (var kvp in this.values)         {             info.AddValue(kvp.Key, kvp.Value);                          }     }  } 

(I guess I could have used an ExpandoObject, but that's another story.)

Here's a simple test program:

    static void Main(string[] args)     {         BinaryFormatter binFmt = new BinaryFormatter();          dynamic obj = new Entity();         dynamic subObj = new Entity();         dynamic obj2 = null;          obj.Value = 100;         obj.Dictionary = new Dictionary<string, int>() { { "la la la", 1000 } };          subObj.Value = 200;         subObj.Name = "SubObject";          obj.Child = subObj;          using (var stream = new FileStream("test.txt", FileMode.OpenOrCreate))         {             binFmt.Serialize(stream, obj);                         }          using (var stream = new FileStream("test.txt", FileMode.Open))         {             try             {                 obj2 = binFmt.Deserialize(stream);                                 }             catch (Exception ex)             {                 Console.WriteLine(ex);             }                         }          Console.ReadLine();      } 

Putting some breakpoints here and there helped me have a look at obj2 contents and it looks like the original data is correctly deserialized, though with the above shortcomings if you get imaginative and move data around.

I had a look at Marc Gravell's protobuf-net, but I'm not really sure how to use it in such a context (I'm not even sure I picked up the right version from the repository, but hey).

I know it's more code than words, but I don't think I can explain the scenario any better. Please do tell if there's something I can add to make this question clearer.

Any help is much appreciated.

like image 340
Raine Avatar asked Jun 16 '10 16:06

Raine


People also ask

What are the types of serialization?

There are three types of serialization in . Net : Binary Serialization, SOAP Serialization and XML Serialization.

What is meant by object serialization?

To serialize an object means to convert its state to a byte stream so way that the byte stream can be reverted back into a copy of the object. A Java object is serializable if its class or any of its superclasses implements either the java. io. Serializable interface or its subinterface, java.

What is dynamic type C#?

In C# 4.0, a new type is introduced that is known as a dynamic type. It is used to avoid the compile-time type checking. The compiler does not check the type of the dynamic type variable at compile time, instead of this, the compiler gets the type at the run time.


2 Answers

I'm 98% certain that this sequence will work for a dynamic object.

  1. convert object to an Expando Object
  2. cast expando object to be of type Dictionary
  3. use ProtoBuf-net Serializer.Serialize / .Deserialize as per normal
  4. convert dictionary to Expando Object

You can convert objects to a collection of name/value pairs for transfering.

That's just a small subset of what dynamic can do, but perhaps it is enough for you.

There's some custom code to handle some of the conversions above that I can show you if there's interest.

I don't have a solution for when dynamic is a placeholder to a class. For this case I'd suggest getting the type and using a switch statement to serialize / deserialize as you require. For this last case, you'd need to place a something to indicate which type of generic deserialization that you need (string / id / fully qualified type name / etc). Assumption is that you are dealing with a list of expected types.

Note: Expando implements IDictionary. An Expando is merely merely a list of key/value pairs. ie. the thing you dot into is the key, and the value is the return from whatever chain of functions implements that. There are a set of dynamic interfaces for customising the syntactic sugar experience, but most of the time you wont to look at them.

refs:

  • Dictionary from IDictionary using the constructor -- http://msdn.microsoft.com/en-us/library/et0ke8sz(v=vs.110).aspx
  • IDictionary/Dictionary to Expando -- http://theburningmonk.com/2011/05/idictionarystring-object-to-expandoobject-extension-method/
like image 152
sgtz Avatar answered Oct 24 '22 02:10

sgtz


I am not sure if JSON would be acceptable in your senario, but if it is I have used Json.net (http://json.codeplex.com) to serialize a dynamic types. It works quite well, it is fast, and the output is small in size. While Json.net doesn't return dynamic objects directly, it is very easy to convert the deserialized output of Json.Net to any dynamic type. In the example below I am using ExpandoObject as my dynamic type. The code below is what I have used in the Facebook Graph Toolkit. See this link for the original source: http://facebookgraphtoolkit.codeplex.com/SourceControl/changeset/view/48442#904504

public static dynamic Convert(string s) {             object obj = Newtonsoft.Json.JsonConvert.DeserializeObject(s);             if (obj is string) {                 return obj as string;             } else {                 return ConvertJson((JToken)obj);             }     }      private static dynamic ConvertJson(JToken token) {         // FROM : http://blog.petegoo.com/archive/2009/10/27/using-json.net-to-eval-json-into-a-dynamic-variable-in.aspx         // Ideally in the future Json.Net will support dynamic and this can be eliminated.         if (token is JValue) {             return ((JValue)token).Value;         } else if (token is JObject) {             ExpandoObject expando = new ExpandoObject();             (from childToken in ((JToken)token) where childToken is JProperty select childToken as JProperty).ToList().ForEach(property => {                 ((IDictionary<string, object>)expando).Add(property.Name, ConvertJson(property.Value));             });             return expando;         } else if (token is JArray) {             List<ExpandoObject> items = new List<ExpandoObject>();             foreach (JToken arrayItem in ((JArray)token)) {                 items.Add(ConvertJson(arrayItem));             }             return items;         }         throw new ArgumentException(string.Format("Unknown token type '{0}'", token.GetType()), "token");     } 
like image 25
Nathan Totten Avatar answered Oct 24 '22 01:10

Nathan Totten