Json.NET - 直接从流反序列化为动态?

Posted

技术标签:

【中文标题】Json.NET - 直接从流反序列化为动态?【英文标题】:Json.NET - deserialize directly from a stream to a dynamic? 【发布时间】:2014-05-05 16:59:42 【问题描述】:

在 Json.NET 文档中 performance tips 的帮助下,我整理了一种从远程资源下载/反序列化 JSON 的方法:

public async Task<T> GetJsonAsync<T>(string url) 

  using (var stream = await new HttpClient().GetStreamAsync(url))
  
    using (var sr = new StreamReader(stream))
    
      using (var jr = new JsonTextReader(sr))
      
        return new JsonSerializer().Deserialize<T>(jr);
      
    
  

我想要一个返回dynamic 的非通用版本。使用GetJsonAsync&lt;dynamic&gt;(url) 调用上述方法有效,直到您尝试访问结果上的动态属性,此时我得到:

'Newtonsoft.Json.Linq.JObject' does not contain a definition for '[MyProperty]'

我已经从字符串中看到how to deserialize to a dynamic,但还没有看到直接从流中执行此操作的工作示例,因为它更节省内存,因此更可取。这可能吗?

【问题讨论】:

你确定你有一个包含 json 的流,并且在你访问它的任何位置都有一个带有 MyProperty 的 json?你能用MemoryStream 制作这个吗? 绝对确定。我用 MyProperty 创建了一个类,并使用它 (GetJsonAsync&lt;MyClass&gt;) 测试了相同的端点,它返回的正是我所期望的。动态版本不行。 【参考方案1】:

事实证明,这与 Json.NET 无关,更多的是与我对动力学的理解(我很少使用)有关。感谢@Peter Richie,我发现如果我将 MyProperty 显式转换为字符串,GetJsonAsync&lt;dynamic&gt; 确实有效。但我宁愿不必那样做。使用我原来的方法和real working endpoint,这里有3个场景;只有最后一个有效:

var url = "http://echo.jsontest.com/MyProperty/MyValue"; // great testing site!

var x1 = await GetJsonAsync<dynamic>(url);
Assert.AreEqual("MyValue", x1.MyProperty); // fail!

dynamic x2 = await GetJsonAsync<dynamic>(url);
Assert.AreEqual("MyValue", x2.MyProperty); // fail!

dynamic x3 = await GetJsonAsync<ExpandoObject>(url);
Assert.AreEqual("MyValue", x3.MyProperty); // pass!

有了这些知识,我的原始方法的非泛型重载如下所示:

public async Task<dynamic> GetJsonAsync(string url) 
    dynamic d = await GetJsonAsync<ExpandoObject>(url);
    return d;

用户可以这样做:

var x = await GetJsonAsync(url);
Assert.AreEqual("MyValue", x.MyProperty); // pass!

【讨论】:

【参考方案2】:

听起来您还没有提供一些信息。以下对我来说很好:

    private T ReadJson<T>(Stream stream)
    
        using (var reader = new StreamReader(stream))
        
            using (var jr = new JsonTextReader(reader))
            
                dynamic d = new JsonSerializer().Deserialize(jr);
                return d;
            
        
    
//...

var d = ReadJson<dynamic>(new MemoryStream(Encoding.UTF8.GetBytes("'MyProperty' : 'MyValue'")));
Debug.WriteLine((String)d.MyProperty);

【讨论】:

谢谢,您将 MyProperty 显式转换为字符串,这为我指明了正确的方向。 是的,从技术上讲,MyProperty 属性是JValue 的一种类型——它没有隐式转换为string

以上是关于Json.NET - 直接从流反序列化为动态?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Json.net 将 JSON 对象反序列化为动态对象

一次反序列化json数组流一项

将 JSON 反序列化为 C# 类,其中 JSON 中的属性名称是动态的

Json.NET:将嵌套数组反序列化为强类型对象

如何使用 System.Text.Json 将 json 字符串或流反序列化到 Dictionary<string,string>

JSON.Net 将集合序列化为数组数组