Turn ExpandoObject into static type

As many oth­ers have shown, the new ExpandoOb­ject intro­duced in C# 4 can be pretty use­ful in some scenarios.

How­ever, on the odd occa­sion when you want to con­vert an ExpandoOb­ject to a sta­tic type you have defined you can be for­given for feel­ing a lit­tle lost as there are no well doc­u­mented ways to do that. At least that’s how I felt, until I found out about the Con­vert­To­Type meth­ods on the JavaScript­Se­ri­al­izer!


The JavaScript­Se­ri­al­izer, like the Dat­a­Con­trac­tJ­son­Se­ri­al­izer class, lets you seri­al­ize and dese­ri­al­ize objects to and from JSON string. But unlike the Dat­a­Con­trac­tJ­son­Se­ri­al­izer class, you are not con­fined to work­ing with types that are marked with the Dat­a­Con­tract attribute.

One of the dese­ri­al­iza­tion meth­ods on the JavaScript­Se­ri­al­izer class – Dese­ri­al­izeOb­ject – lets you a JSON string to an object graph, i.e. a Dictionary<string, object> object where the key is the name of the prop­erty and the value is the prop­erty value. And you can use one of the over­loaded Con­vert­To­Type meth­ods to con­vert this dic­tio­nary to a sta­tic type of your choice, pro­vided that the type has a para­me­ter­less con­struc­tor (which unfor­tu­nately, means you won’t be able to con­vert an ExpandoOb­ject to an anony­mous type).

ExpandoOb­ject as IDictionary<string, object>

Why is this impor­tant? It’s because the ExpandoOb­ject imple­ments the IDictionary<string, object> inter­face and there­fore can be used with the Con­vert­To­Type methods!

Here’s what you do:

   1: // first you need to instantiate the serializer

   2: var jsSerializer = new JavaScriptSerializer();


   4: // get an expando object and convert it to an instance of MyClass

   5: var expando = GetExpandoObject();

   6: var obj = jsSerializer.ConvertToType<MyClass>(expando);


   8: Console.WriteLine(obj.Id);      // 0db9d9a6-8c7e-4bea-82a8-4d5641c7c0de

   9: Console.WriteLine(obj.Name);    // Yan

  10: Console.WriteLine(obj.Age);     // 29


  12: ...


  14: public ExpandoObject GetExpandoObject()

  15: {

  16:     dynamic expando = new ExpandoObject();

  17:     expando.Id = Guid.NewGuid();

  18:     expando.Name = "Yan";

  19:     expando.Age = 29;


  21:     return expando;

  22: }


  24: public class MyClass

  25: {

  26:     public Guid Id { get; set; }


  28:     public string Name { get; set; }


  30:     public int Age { get; set; }

  31: }

Pretty cool, eh? ;-)

But what if the shape of the expando object doesn’t match your type? E.g. there are prop­er­ties defined on MyClass but not on the expando object, or vice versa, or both? Well, it’s smart enough to work that out itself and only set the prop­er­ties which it is able to set:

   1: // same as before


   3: Console.WriteLine(obj.Id);          // 0db9d9a6-8c7e-4bea-82a8-4d5641c7c0de

   4: Console.WriteLine(obj.Name);        // null

   5: Console.WriteLine(obj.Age);         // 29

   6: Console.WriteLine(obj.NickName);    // null


   8: ...


  10: public ExpandoObject GetExpandoObject()

  11: {

  12:     dynamic expando = new ExpandoObject();

  13:     expando.Id = Guid.NewGuid();

  14:     expando.Name = "Yan";

  15:     expando.Age = 29;

  16:     expando.Wife = "Yinan";    // not defined on MyClass


  18:     return expando;

  19: }


  21: public class MyClass

  22: {

  23:     public Guid Id { get; set; }


  25:     public string Name { get; private set; } // non-public setter


  27:     public int Age { get; set; }


  29:     public string NickName { get; set; } // not defined on ExpandoObject

  30: }

  • ciantic

    You are using “JavaScriptSerializer.ConvertToType” won­der if there is a bet­ter way? Asp.Net uses New­ton­soft Json, but I can’t find any­thing equiv­a­lent from it.

    Also one would think ExpandoOb­ject could do it itself with­out seri­al­iza­tions, but appar­ently not.

  • Yan Cui


    The ‘JavaScriptSerializer.ConvertToType‘ was the one I found at the time, and it is con­ve­nient but I doubt it per­forms very well (JavaScript­Se­ri­al­izer per­forms very poorly in gen­eral in all my bench­mark tests).

    I’d have thought Json.net (i.e. Newtonsoft.json) has some­thing sim­i­lar, though I’ve never really looked for it, maybe drop a ques­tion on Stack­Over­flow and see if some­one more famil­iar with Json.Net can give you the answer.

    Alter­na­tively, if you don’t mind get­ting your hands dirty, you can also just DIY it, and it would be pretty easy too, Jon Har­rop pub­lished an arti­cle a few years back on his F# Jour­nal describ­ing how to do struc­tural typ­ing with F#‘s dynamic oper­a­tor (?) : http://fsharpnews.blogspot.co.uk/2012/09/structural-typing.html
    I find it a very good read, and there were a few follow-up arti­cles on using IL emit in gen­eral which you might find inter­est­ing too, and hope­fully help jus­tify the cost of get­ting access to the arti­cles. His solu­tion is more gen­eral pur­pose but won’t work on ExpandoOb­ject purely because reflect­ing on ExpandoOb­ject won’t give you the dynam­i­cally added prop­er­ties, nonethe­less it’d give you a nice frame­work to think about a solu­tion that will work though.

    Ulti­mately, the steps to a DIY solu­tion (that works on an ExpandoOb­ject) is pretty sim­ple:
    1. reflect on the tar­get type to iden­tify prop­er­ties
    2. cast the ExpandoOb­ject to IDic­tionary
    3. instan­ti­ate an instance of the tar­get type
    4. for each prop­erty, find the key in the dic­tio­nary, and use the matched value to set the prop­erty with
    There are other edge cases to con­sider, e.g. get-only prop­er­ties, pri­vate set­ters, abstract tar­get type, etc. but as an easy solu­tion the above should work. To cover the edge cases you might be bet­ter off cre­at­ing a dynam­i­cally gen­er­ated proxy type that inher­its from the tar­get, and set the prop­er­ties on the proxy type instead.

    Now that I’ve typed all that, maybe it’d be eas­ier if I just do an updated post to show how you might do that.. If you’re still inter­ested, I can put some­thing together this week­end perhaps.