【问题标题】:How can I derive a C# dynamic object from a web api JSON reponse?如何从 Web api JSON 响应中驱动 C# 动态对象?
【发布时间】:2017-07-14 18:46:39
【问题描述】:

在大多数情况下,默认情况下,我们没有在我们选择的静态语言中定义类,这让白在如何反序列化例如JSON 从对公共和开放 wen api 的调用返回,专用于没有单一语言,除了例如的“语言”。 HTML 和 JSON。

如今,在 .NET 中,几乎所有 api 查询都使用 HttpClient 完成,类似于下面的 Google Books API ISBN 查询:

public class GoogleBooksClient
{
    private const string IsbnUrl = "books/v1/volumes?q=isbn:{0}";
    private static HttpClient _client = new HttpClient();
    ...
    public async Task<object> GetDetailsByIsbn(string isbn)
    {
        var json = await _client.GetStringAsync(string.Format(IsbnUrl, isbn));
        dynamic objX = JsonConvert.DeserializeObject(json);
        return objX;
    }
}

这里最大的问题是objX是否被声明为var'、objectdynamic,当DeserializeObject被调用时,它总是引用一个又大又丑的JObject实例已知类型。在这种情况下,返回的 JSON 对象非常复杂,等待那些努力编写可以解析 JSON 的 C# 类的人。

这是使用 C# dynamic 对象的理想且有意的机会,在解析 JSON 时,可以将属性(很少用于 API 响应的函数)递归地添加到所述动态对象中。

相反,NewtonSoft.JSON 将 JSON 保存的数据与非常不透明的 Jobject 数据结构的繁文缛节紧密结合在一起。我很惊讶也很失望,到目前为止,NewtonSoft 不能简单地提取一个纯动态对象,而没有他们JObject 迷宫的所有令人费解的官僚机构。

有没有其他方法可以简单地将 JSON 解析为 C# 动态对象,就像在其他场景中将其解析为显式动态 JavaScript 对象一样?

添加:混淆他们 JObject 迷宫的官僚作风”,我的意思是以下代码:

var json = JsonConvert.SerializeObject(new Person {Id = 196912135012878, Age = 47, Name = "Brady"});
var jObj = JsonConvert.DeserializeObject(json);

产生一个JObject 实例,我的调试器显示为:

在我看来,这更像是在解析 JSON 期间应该在内部使用的东西,而不是解析的最终产品,它应该是仅从该 JSON 解析的属性的纯粹表示。理想情况下,这将是一个没有任何属性的 C# 动态对象,可供任何解析器使用。

【问题讨论】:

  • 对于JObject 类型的令牌(而不是JArray),您可以反序列化为ExpandoObject。见newtonsoft.com/json/help/html/SerializationGuide.htm#Dynamic。不太确定你的问题是什么。 混淆他们 JObject 迷宫的官僚作风是什么意思?
  • @dbc 添加了我不喜欢JObject 的原因。感谢ExpandoObject 提示。这确实很有帮助。
  • @dbc 顺便说一下,dman2306 的链接与JObjectdynamic 以及JArray 一样有效。虽然我认为我的最终目标是将 Json.NET 配置为始终在输出 json 中包含类型名称,但我可以为该类型做一个快速的脏樱桃挑选,然后正确反序列化为类型。我并不总是自己做序列化:ASP.NET 经常为我做。
  • @dbc 请让ExpandoObject 解决方案成为我会接受的答案。感觉恰到好处,并且省略了外部的非 BCL 类。

标签: c# json serialization dynamic json.net


【解决方案1】:

您可以反序列化为ExpandoObject,而不是JObject,这由Json.NET 的内置转换器ExpandoObjectConverter 支持。如果是数组,您可以反序列化为List&lt;ExpandoObject&gt;,然后选择为List&lt;dynamic&gt;。如果是原始值,则可以返回 JValue.Value

例如,如果您事先知道您的 JSON 表示一个对象,那么就这样做:

dynamic dyn = JsonConvert.DeserializeObject<ExpandoObject>(json);

如果您事先不知道根 JSON 容器可能是什么,可以将其加载为 JToken 并使用以下扩展方法:

public static class JsonExtensions
{
    public static dynamic ToDynamic(this JToken token)
    {
        if (token == null)
            return null;
        else if (token is JObject)
            return token.ToObject<ExpandoObject>();
        else if (token is JArray)
            return token.ToObject<List<ExpandoObject>>().Cast<dynamic>().ToList();
        else if (token is JValue)
            return ((JValue)token).Value;
        else
            // JConstructor, JRaw
            throw new JsonSerializationException(string.Format("Token type not implemented: {0}", token));
    }
}

然后做:

dynamic dyn = JsonConvert.DeserializeObject<JToken>(json).ToDynamic();

示例fiddle

【讨论】:

  • ExpandoObjectConverter 是要走的路,IMO。如果您想利用动态语言运行时,这是语法最简洁的选项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-16
  • 2022-07-30
  • 2017-02-25
  • 2021-11-24
  • 1970-01-01
  • 2014-09-24
  • 2023-03-29
相关资源
最近更新 更多