1

I use JavaScriptSerializer to serialize a json string to a specific Class

Here is the origin json string:

{
   "status":0,
   "data":[
          {
             "username":"yong6180212856@163.com",
             "password":"r2166745"
          }, 
          {
             "username":"xinnai1122139@163.com",
             "password":"f0341303"
          }
          ],
   "msg":"OK"
}

This is a structured responsed from a http server, and the data field will differ from different request. So in the RetData class I don't wan't to make a fixed type of data and just using Object then downcast to corresponding type when needed.

 class RetData {
    public int status {get;set;}
    public string msg {get;set;}
    public List<Object> data {get;set;}
 }

After using

 RetData retData = new JavaScriptSerializer<RetData>(jsonStr);

Then I want to retrive the each password like this:

foreach (var item in retData.data){
   // some thing like this but I really don't know which type 
   // should I downcast to here.
   //                  |
   //                  V
   string password = ((??map??)item).getString("password"); 
   Console.WriteLine(password);
}

As you can see, what type should I downcast to, to retrieve the password flied, I am sort of familiar with Java but quite a newbie of C#, need some help.

armnotstrong
  • 8,605
  • 16
  • 65
  • 130

3 Answers3

0

There are lots of approaches here. The shortest path from where you are would be to change RetData to this:

public class RetData
{
    public int status { get; set; }
    public string msg { get; set; }
    public List<Dictionary<object,object>> data { get; set; }
}

Then read the data like this:

RetData retData = (RetData)new JavaScriptSerializer().Deserialize(jsonStr, typeof(RetData));

foreach (var item in retData.data)
{
    string password = item["username"].ToString();
    Console.WriteLine(password);
}

The limitation is that this will really only work with simple name/value pairs. The other approach would be to change to use Newtonsoft Json, instead of the Microsoft Json. This has a type called "JObject" which can handle truly any kind of Json data. Newtonsoft Json is available as a nuget package.

My comment about dynamic was wrong. I tried it and it turns out that the .NET serializer doesn't understand dynamic or ExpandoObject. :-(

Moby Disk
  • 3,761
  • 1
  • 19
  • 38
0

When you deserialize JSON with JavaScriptSerializer into an object property or field, the serializer will recursively choose the most appropriate representation to which to deserialize each JSON element therein:

This allows completely generic JSON data to be deserialized and used.

Some extension methods that are helpful in working with untyped deserialized JSON from JavaScriptSerializer include:

public static class JavaScriptSerializerObjectExtensions
{
    public static object JsonElementAt(this object obj, int index)
    {
        if (index < 0)
            throw new ArgumentException();
        var array = obj as object[];
        if (array == null || index >= array.Length)
            return null;
        return array[index];
    }

    public static object JsonPropertyAt(this object obj, string name)
    {
        var dict = obj as IDictionary<string, object>;
        if (dict == null)
            return null;
        object value;
        if (!dict.TryGetValue(name, out value))
            return null;
        return value;
    }

    public static bool IsJsonArray(this object obj)
    {
        return obj is object[];
    }

    public static object [] AsJsonArray(this object obj)
    {
        return obj as object[];
    }

    public static bool IsJsonObject(this object obj)
    {
        return obj is IDictionary<string, object>;
    }

    public static IDictionary<string, object> AsJsonObject(this object obj)
    {
        return obj as IDictionary<string, object>;
    }

    public static bool IsJsonNumber(this object obj)
    {
        if (obj == null)
            return false;
        switch (Type.GetTypeCode(obj.GetType()))
        {
            case TypeCode.Int32:
            case TypeCode.Int64:
            case TypeCode.Decimal:
            case TypeCode.Double:
                return true;

            case TypeCode.Byte:
            case TypeCode.SByte:
            case TypeCode.UInt16:
            case TypeCode.UInt32:
            case TypeCode.UInt64:
            case TypeCode.Int16:
            case TypeCode.Single:
                Debug.WriteLine("Unexpected integer type " + Type.GetTypeCode(obj.GetType()));
                return true;

            default:
                return false;
        }
    }

    public static bool IsJsonBoolean(this object obj)
    {
        return obj is bool;
    }

    public static bool IsJsonString(this object obj)
    {
        return obj is string;
    }

    public static bool IsDateTime(this object obj)
    {
        return obj is DateTime;
    }

    [Conditional("DEBUG")]
    public static void DebugWriteJson(this object obj)
    {
        var sb = obj.DumpJson();
        Debug.WriteLine(sb);
    }

    public static string DumpJson(this object obj)
    {
        var sb = obj.DumpJson(new StringBuilder(), 0, false, string.Empty);
        return sb.ToString();
    }

    static StringBuilder DumpJson(this object obj, StringBuilder sb, int level, bool isPropertyValue, string postfix)
    {
        if (obj == null)
            return sb;
        string prefix = new string(' ', 2 * level);
        if (obj is IList<object>)
        {
            var array = (IList<object>)obj;
            if (isPropertyValue)
                sb.AppendLine();
            sb.AppendLine(prefix + "[");
            for (int i = 0; i < array.Count; i++)
            {
                array[i].DumpJson(sb, level + 1, false, (i == array.Count - 1 ? string.Empty : ","));
            }
            sb.AppendLine(prefix + "]" + postfix);
        }
        else if (obj is IDictionary<string, object>)
        {
            if (isPropertyValue)
                sb.AppendLine();
            sb.AppendLine(prefix + "{");
            var dict = ((IDictionary<string, object>)obj).ToList();
            for (int i = 0; i < dict.Count; i++)
            {
                sb.AppendFormat("{0}  \"{1}\" : ", prefix, dict[i].Key);
                dict[i].Value.DumpJson(sb, level + 2, true, (i == dict.Count - 1 ? string.Empty : ","));
            }
            sb.AppendLine(prefix + "}" + postfix);
        }
        else if (obj.IsJsonString())
        {
            string initialPrefix = (isPropertyValue ? "" : prefix);
            sb.AppendLine(initialPrefix + '"' + obj.ToString() + '"' + postfix);
        }
        else
        {
            string initialPrefix = (isPropertyValue ? "" : prefix);
            sb.AppendLine(initialPrefix + obj.ToString().ToLower() + postfix);
        }
        return sb;
    }

Then you could do something like:

class RetData
{
    public int status { get; set; }
    public string msg { get; set; }
    public object data { get; set; }
}

        var retData = (new JavaScriptSerializer()).Deserialize<RetData>(jsonStr);

        if (retData.data.IsJsonArray())
            foreach (var obj in retData.data.AsJsonArray())
                if (obj.JsonPropertyAt("username") != null)
                    Console.WriteLine(obj.JsonPropertyAt("password"));

Or, if it looks more familiar:

        if (retData.data.IsJsonArray())
            foreach (var obj in retData.data.AsJsonArray())
                if (obj.IsJsonObject())
                {
                    var map = obj.AsJsonObject();
                    if (map.ContainsKey("username") && map.ContainsKey("password"))
                        Console.WriteLine(map["password"]);
                }

Honestly, however, this is close to re-inventing Linq-to-Json so you might want to investigate switching to Json.NET.

dbc
  • 104,963
  • 20
  • 228
  • 340
-1

Use the dynamickey word to define the type of data:

class RetData
{
    public int status { get; set; }
    public string msg { get; set; }
    public dynamic data { get; set; }
}

Note that this will take away intellisense and compiliation verifications, which means responsibility for checking the type is yours.

Alternatively, with a little bit more details about your design, you might be able to create a base data class, than inherit and implement it for your different data types.

Shy Agam
  • 1,285
  • 1
  • 13
  • 37
  • Thanks I'll try that, could you be more specific about create a base data class? I don't quite follow that. – armnotstrong Mar 11 '15 at 15:07
  • As I said, more details are needed. But just to inspire your imagination: - Make an abstract class (Let's call it MyData) - Make an abstract property or method "GetPassword" - Inherit the class and implement GetPassword in different ways – Shy Agam Mar 11 '15 at 15:15