C#反序列化动态JSON

3
我有以下需要反序列化的Json字符串。
{"123456789":
  {"short_description":"Delivered",
     "detail_description":"Your item has been delivered"
   }
}

第一个字段“123456789”是一个id号码,因此基本上这个值可以根据查询的数据而有所不同。我在Visual Studio中使用C#。显然,由于第一个字段的值可以更改,因此我不能使用预定义类将JSON反序列化,因为此字段将用作类名,但字段值将与类名不匹配。有没有一种方法可以将其反序列化为某种动态类,但仍可以像预定义类一样访问字段?或者是否有一种方法可以将其反序列化为预定义类,即使类名不匹配?提供此数据的服务是第三方服务,因此我无法控制它。

请查看 http://www.newtonsoft.com/json/help/html/deserializeobject.htm。 - KingRider
2个回答

5

这是我在生产代码中使用的一种方法。它可能不完美,但它可以完成工作。

using using System.Web.Script.Serialization;

// .....

    public object GetJson(string url)
    {
        var json = Get(url); // I have code that makes this work, it gets a JSON string

        try
        {
            var deserializer = new JavaScriptSerializer();
            var result = deserializer.DeserializeObject(json);

            return result;
        }
        catch (ArgumentException e)
        {
            // Error handling....
        }            
    }

您收到的对象将是通用的Map、List或其他,具体取决于JSON的结构。如果您知道预期的结构,那么这非常有用,而不需要编写自定义解析器或目标对象类型。
例如,您可以枚举Map的键,以找到变化的键。然后,包装器或转换将为应用程序层提供一致的API。类似于:
public class Order {
     public string OrderNum { private set; get; }
     public string ShortDesc { private set; get; }
     public string Desc { private set; get; }

     public static Order FromJson(object jsonResult) 
     {
          var m = jsonResult as Map<string, object>;

          // Handle errors, but I am not

          var firstPair = m.First();

          var detail = firstPair.Value as Map<string, object>;

          var dummy = new Order()
          {
              OrderNum = firstPair.Key,
              ShortDesc = detail["short_description"].ToString();
              Desc = detail["detail_description"].ToString();
          }

          return dummy;
     }
}

3

我喜欢上面的答案,所以我稍微重构了一下。您需要引用 System.Web.Extensions.dllSystem.Web.Script.Serialization

以下是类:

public class Order
{
    public string OrderNum { private set; get; }
    public string ShortDesc { private set; get; }
    public string Desc { private set; get; }

    public static Order FromJson(string jsonResult) 
    {
        JavaScriptSerializer js = new JavaScriptSerializer();
        // Should deserialize right to Dictionary<string, object>
        // var result = ((Dictionary<string, object>)js.Deserialize<dynamic>(jsonResult)).First();
        var result = js.Deserialize<Dictionary<string, object>>(jsonResult).First();
        var detail = (Dictionary<string, object>)result.Value;

        return new Order()
        {
            OrderNum = result.Key,
            ShortDesc = detail["short_description"].ToString(),
            Desc = detail["detail_description"].ToString()
        };
    }
}

如何调用它:

string json = "{\"123456789\": {\"short_description\":\"Delivered\", \"detail_description\":\"Your item has been delivered\" } }";
Order o = Order.FromJson(json);

不过,你需要自己实现错误处理。


很酷...... :-) 生产代码需要更多的错误处理,但 :-) 我喜欢这个动态技巧。我不确定当我第一次开始使用这种方法或其祖先时,C# 是否有动态功能,而且我从未更新过我的技术。 - SAJ14SAJ
仅考虑此情况,您甚至不需要动态类型。可以直接反序列化为“Dictionary<string, object>”(我提供了一个编辑)。如果Json格式良好,则dynamic返回将在没有所有Key/Value调用的情况下工作。 - Joey Gennari
这很有道理。我的代码片段是通用的,这就是为什么我反序列化为对象的原因。我的技术基于我实际所做的事情,并不是针对一个特定情况进行优化,就像你展示的那样。有时我会得到地图列表,有时是地图,有时甚至只是字符串或其他东西。这是我从HTTP / HTML / JSON源(通常是Domino数据库,但你明白我的意思)中提取数据的ETL库的一部分。还有一个Xml等效物和更多包装器,但它们没有出现 :-) - SAJ14SAJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接