Using C# 4.0 and dynamic to parse JSON

An alternative deserialisation approach is suggested here. I modified the code slightly to fix a bug and suit my coding style. All you need is this:

View Code
  1  using System;
  2  using System.Collections;
  3  using System.Collections.Generic;
  4  using System.Collections.ObjectModel;
  5  using System.Dynamic;
  6  using System.Linq;
  7  using System.Text;
  8  using System.Web.Script.Serialization;
  9 
 10  private  sealed  class DynamicJsonConverter : JavaScriptConverter
 11 {
 12      public  override  object Deserialize(IDictionary< stringobject> dictionary, Type type, JavaScriptSerializer serializer)
 13     {
 14          if (dictionary ==  null)
 15              throw  new ArgumentNullException( " dictionary ");
 16 
 17          return type ==  typeof( object) ?  new DynamicJsonObject(dictionary) :  null;
 18     }
 19 
 20      public  override IDictionary< stringobject> Serialize( object obj, JavaScriptSerializer serializer)
 21     {
 22          throw  new NotImplementedException();
 23     }
 24 
 25      public  override IEnumerable<Type> SupportedTypes
 26     {
 27          get {  return  new ReadOnlyCollection<Type>( new List<Type>( new[] {  typeof( object) })); }
 28     }
 29 
 30      #region Nested type: DynamicJsonObject
 31 
 32      private  sealed  class DynamicJsonObject : DynamicObject
 33     {
 34          private  readonly IDictionary< stringobject> _dictionary;
 35 
 36          public DynamicJsonObject(IDictionary< stringobject> dictionary)
 37         {
 38              if (dictionary ==  null)
 39                  throw  new ArgumentNullException( " dictionary ");
 40             _dictionary = dictionary;
 41         }
 42 
 43          public  override  string ToString()
 44         {
 45              var sb =  new StringBuilder( " { ");
 46             ToString(sb);
 47              return sb.ToString();
 48         }
 49 
 50          private  void ToString(StringBuilder sb)
 51         {
 52              var firstInDictionary =  true;
 53              foreach ( var pair  in _dictionary)
 54             {
 55                  if (!firstInDictionary)
 56                     sb.Append( " , ");
 57                 firstInDictionary =  false;
 58                  var value = pair.Value;
 59                  var name = pair.Key;
 60                  if (value  is  string)
 61                 {
 62                     sb.AppendFormat( " {0}:\"{1}\" ", name, value);
 63                 }
 64                  else  if (value  is IDictionary< stringobject>)
 65                 {
 66                      new DynamicJsonObject((IDictionary< stringobject>)value).ToString(sb);
 67                 }
 68                  else  if (value  is ArrayList)
 69                 {
 70                     sb.Append(name +  " :[ ");
 71                      var firstInArray =  true;
 72                      foreach ( var arrayValue  in (ArrayList)value)
 73                     {
 74                          if (!firstInArray)
 75                             sb.Append( " , ");
 76                         firstInArray =  false;
 77                          if (arrayValue  is IDictionary< stringobject>)
 78                              new DynamicJsonObject((IDictionary< stringobject>)arrayValue).ToString(sb);
 79                          else  if (arrayValue  is  string)
 80                             sb.AppendFormat( " \"{0}\" ", arrayValue);
 81                          else
 82                             sb.AppendFormat( " {0} ", arrayValue);
 83 
 84                     }
 85                     sb.Append( " ] ");
 86                 }
 87                  else
 88                 {
 89                     sb.AppendFormat( " {0}:{1} ", name, value);
 90                 }
 91             }
 92             sb.Append( " } ");
 93         }
 94 
 95          public  override  bool TryGetMember(GetMemberBinder binder,  out  object result)
 96         {
 97              if (!_dictionary.TryGetValue(binder.Name,  out result))
 98             {
 99                  //  return null to avoid exception.  caller can check for null this way...
100                 result =  null;
101                  return  true;
102             }
103 
104              var dictionary = result  as IDictionary< stringobject>;
105              if (dictionary !=  null)
106             {
107                 result =  new DynamicJsonObject(dictionary);
108                  return  true;
109             }
110 
111              var arrayList = result  as ArrayList;
112              if (arrayList !=  null && arrayList.Count >  0)
113             {
114                  if (arrayList[ 0is IDictionary< stringobject>)
115                     result =  new List< object>(arrayList.Cast<IDictionary< stringobject>>().Select(x =>  new DynamicJsonObject(x)));
116                  else
117                     result =  new List< object>(arrayList.Cast< object>());
118             }
119 
120              return  true;
121         }
122     }
123 
124      #endregion
125 }

You can use it like this:

View Code
1  string json = ...;
2 
3  var serializer =  new JavaScriptSerializer();
4 serializer.RegisterConverters( new[] {  new DynamicJsonConverter() });
5 
6 dynamic obj = serializer.Deserialize(json,  typeof( object));

So, given a JSON string: 

 

View Code
1 {
2    " Items ":[
3     {  " Name ": " Apple "" Price ": 12.3 },
4     {  " Name ": " Grape "" Price ": 3.21 }
5   ],
6    " Date ": " 21/11/2010 "
7 }

The following code will work at runtime:

 

View Code
1  var data = serializer.Deserialize(json,  typeof( object));
2 
3 data.Date;  //  "21/11/2010"
4 data.Items.Count;  //  2
5 data.Items[ 0].Name;  //  "Apple"
6 data.Items[ 0].Price;  //  12.3 (as a decimal)
7 data.Items[ 1].Name;  //  "Grape"
8 data.Items[ 1].Price;  //  3.21 (as a decimal)

 

I'm interested in any discussion about this approach.

EDIT

I updated the code to fix a small bug (with lists of complex types) and to include a ToString method that outputs the JSON string, which I found useful for debugging. You can drop the two methods out if you don't want them as they aren't required for deserialisation.

It's pretty simple using Newtonsoft.Json:

View Code
1  var jsonSerializer =  new JsonSerializer();
2 dynamic stuff = jsonSerializer.Deserialize( new JsonTextReader( new StringReader( " { 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 } ")));
3 
4  var name = stuff.Name;
5  var address = stuff.Address.City;

.Net 4.0 has a built-in library to do this:

View Code
1  using System.Web.Script.Serialization;
2 JavaScriptSerializer jss =  new JavaScriptSerializer();
3  var d=jss.Deserialize<dynamic>(str);

This is the simplest way You can use it like this:

View Code
1  (new System.Collections.Generic.Mscorlib_DictionaryDebugView<string,object>(((System.Collections.Generic.Dictionary<string,object>)(obj[0])))).Items[1]

refer to:

http://stackoverflow.com/questions/3142495/deserialize-json-into-c-sharp-dynamic-object

这有一篇介绍动态解析原理的文章:http://www.codeproject.com/Articles/349646/Dynamic-JSON-parser

你可能感兴趣的:(dynamic)