Partager via


Using Anonymous types to deserialize JSON data

While I was playing around with deserializing objects written in JSON format, I noticed that I had to write a lot of classes that were used just to deserialize the JSON response. I noticed that I did not necessarily needed those classes, and that I often would just transfer data from those classes back into my own objects. Basically, I ended up with a lot of classes which were used just to get the JSON response into objects.

I started thinking about how I could leverage C# language features to accomplish the same goals. I this article I am going to show you how you can use the C# 3.0 anonymous types feature to deserialize JSON data back into objects. For parsing JSON and assigning values to my object I will use this JSON implementation.

C# 2.0

The JSON text that I am trying to parse is this:

string JSONText = "{Text:\"Hello World!!\", Status:\"Ok\"}";

In order to do this, I would have to create a class (with any name) that will have the two properties Text and Status:

class HelloWorldResponse
{
    public string Text { get; set; }
    public string Status { get; set; }
}

And now, in order to deserialize the data, I use the JSON serializer like so:

var x = js.Deserialize(new StringReader(JSONText), typeof(HelloWorldResponse)) as HelloWorldResponse;

C# 3.0

In C# 3.0 we introduced the notion of anonymous types - types that have no name that you can speak - that can have any shape you want. The main reason why they were introduced is to support LINQ, but they can be used in other way as well.

So, in C# 3.0 instead of writing my own classes, I decided to let the compiler do the work for me. What I will do is to create the anonymous types in the function that need that response. I will pass the anonymous type to the JSON deserializer and get back an object that contains an anonymous type populated with the data from the JSON string. To get from object to the strongly typed anonymous type, I will use a generic method that casts the object to the type of the anonymous type .

Here is the method that converts object to the anonymous type:

public static class TypeExtension
{
    public static T ToType<T>(this object o, T typeToCastTo)
    {
        return (T)o;
    }
}

This is a generic extension method that takes in two arguments: the object I am trying to convert and the type I am converting to. The compiler will do type inference on the argument going in, so if I pass in a variable of an anonymous type, it will figure out the unspeakable name for the anonymous type. Then, it just returns the result of the converson from the object to that type.

Then, I can just write the code like this:

var helloResponse = new { Text = string.Empty, Status = string.Empty };
var y = js.Deserialize(new StringReader(JSONText), helloResponse.GetType()).ToType(helloResponse);

And then, y will hold a reference to an anonymous type and I can use it to read the properties from the type.

The advantage that I am getting is not in the number of classes that I have to write - the compiler will generate the same number of classes* as I would have.  The disadvantage to this solution is the fact that now I have type definitions inside methods, which can make it harder to debug/change. Also, if your internal classes map directly to the response you get as JSON, then you are probably better off using "real classes".

C# 4.0

In C# 4.0, with the introduction of dynamic, we can further simplify this code. In C# 4.0, I don't need the method that will convert from object to the anonymous type. I can just stick the object returned from the JSON deserializer into a dynamic and use dynamic dispatch to get to the members that I care about:

var helloResponse = new { Text = string.Empty, Status = string.Empty }; 
dynamic y = js.Deserialize(new StringReader(JSONText), helloResponse.GetType());

The disadvantage of this solution is that you will not have IntelliSense one you go dynamic, so any spelling mistake will not be caught by the compiler.

So here you go - 3 ways of doing the same thing, each with their pros and cons. I really like to C# 3.0/ C# 4.0 versions where you create the type "on the fly" and then you go ahead and use result. I still don't like the fact that I need to explicitly state what are the members on the type. I would just like to get "a" type back and then magically get just the members I care about. Well - we'll see :).

*the compiler will try to reuse similar anonymous types, so you might actually get fewer types

Comments

  • Anonymous
    July 07, 2010
    The code above (C# version 4.0) doesn't work.The anonymous class doesn't have a default constructor.This might be something new in release version of C#. The javascript serializer also takes a string now, not a reader.
  • Anonymous
    November 09, 2010
    The 3.0 version doesn't work either. Could you put some source files of working examples here for reference?
  • Anonymous
    November 11, 2010
    What is the error you are seeing with the C# 3.0 version?
  • Anonymous
    January 06, 2011
    The .NET 4.0 method is awesome and makes my life much easier. One note: in your examples, it's not clear which class the "js" in js.Deserialize() refers to.
  • Anonymous
    January 06, 2011
    The .NET 4.0 method is awesome and makes my life much easier. One note: in your examples, it's not clear which class the "js" in js.Deserialize() refers to.
  • Anonymous
    January 06, 2011
    Hey Alex.The js refers to the JSON Deserializer I used - json.codeplex.com/.../ProjectReleases.aspx.Alex
  • Anonymous
    January 12, 2011
    string JSONText = "{Text:"Hello World!!", Status:"Ok"}";var helloResponse = new { Text = string.Empty, Status = string.Empty };var y = JavaScriptConvert.DeserializeObject(JSONText, helloResponse.GetType()).ToType(helloResponse);//now you can access properties with  y.Test and  y.Statu
  • Anonymous
    April 08, 2011
    Thanks, this was the most helpful explanation of JSON deserialization I've come across. I'm mainly interested in how to deserialize custom classes and arrays. Here's one of my JSON service responses:{  "ResultPageNumber":"String content",  "ResultPageTotal":"String content",  "Results":[{     "Group":"String content",     "Size":"String content",     "Subject":"String content",  }]}In SOAP this is easy. With WCF REST I assumed it would also be easy. The only reason to use WCF REST over SOAP in C# is if you're looking at supporting other client types that have poor support for SOAP. (like say Android) I'm not explicitly supporting Android, as I want to implemented a couple of useful clients for the service, but I'm a little disheartened on the client-side JSON support available within .Net. I can parse it all out myself, but this is something that .Net could magically transform for us. (I mean SOAP support is top notch on all sides) Maybe I'm completely missing the boat. I apologize if I am, but any help would be welcome. Thanks.