Json.直接从流反序列化到动态

本文关键字:反序列化 动态 Json | 更新日期: 2023-09-27 17:53:40

在Json中的性能提示的一点帮助下。. NET文档中,我编写了一个从远程资源下载/反序列化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<dynamic>(url)调用上述方法是有效的,直到您尝试访问结果的动态属性,此时我得到:

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

我已经看到了如何从字符串反序列化到动态,但还没有看到直接从流反序列化的工作示例,这将是更可取的,因为它更节省内存。这可能吗?

Json.直接从流反序列化到动态

事实证明这与Json关系不大。NET和更多与我对动态的理解有关(我很少使用)。感谢@Peter Richie,我发现GetJsonAsync<dynamic>确实工作,如果我显式地将MyProperty转换为字符串。但我不想这么做。使用我最初的方法和一个真实的工作端点,这里有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!

听起来你好像还有一些信息没有提供。下面的工作对我来说很好:

    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);