【问题标题】:How to deserialize ReadOnlySpan<char> to object using System.Text.Json如何使用 System.Text.Json 将 ReadOnlySpan<char> 反序列化为对象
【发布时间】:2019-11-13 21:27:10
【问题描述】:

当我得到一个非常大的文本数据并且每行包含一些元数据 + json 数据字符串时,我有一个案例。 我需要处理每一行的json数据。

这就是我所拥有的:

public Data GetData(string textLine)
{
    var spanOfLine = textLine.AsSpan();
    var indexOfComma = spanOfLine.IndexOf(":");
    var dataJsonStringAsSpan = spanOfLine.Slice(indexOfComma + 1);

    // now use dataJsonStringAsSpan which is ReadOnlySpan<char> to deserialize the Data
}

Data 是一个 Dto 类,它有一堆 (7) 个不同的属性:

public class Data
{
    public int Attribute1 { get; set; }

    public double Attribute2 { get; set; }
    // ... more properties, emitted for the sake of brevity
}

我正在尝试使用System.Text.Json API 来实现这一点。令人惊讶的是它没有从ReadOnlySpan&lt;char&gt; 反序列化的任何重载,所以我想出了这个:

public Data GetData(string textLine)
{
    var spanOfLine = textLine.AsSpan();
    var indexOfComma = spanOfLine.IndexOf(":");
    var dataJsonStringAsSpan = spanOfLine.Slice(indexOfComma + 1);

    var byteCount = Encoding.UTF8.GetByteCount(dataJsonStringAsSpan);
    Span<byte> buffer = stackalloc byte[byteCount];
    Encoding.UTF8.GetBytes(dataJsonStringAsSpan, buffer);
    var data = JsonSerializer.Deserialize<Data>(buffer);
    return data;
}

虽然这可行,但看起来非常复杂。

这是要走的路还是我错过了更简单的东西?

【问题讨论】:

  • 是否有特殊原因需要将每行文本转换为跨度..?字符串在 json api 中更容易使用和原生工作,如果你已经得到了一个字符串,为什么不直接取包含 json 数据的子字符串呢?
  • 如果您的文本“非常大”并且您不想为其创建 String 对象,那么您 - 绝对 - 不想要 stackalloc。您可以反序列化dataJsonStringAsSpan.ToString()ReadOnlySpan&lt;char&gt; 上的 ToString 是“将这些内容复制到字符串”,而不是“作为调试辅助/显示值”)
  • 您能否请edit 分享您尝试反序列化的 JSON 的(简化)示例?此外,如果您的 JSON 非常大,那么您一开始就不想将其加载到单个 string 中,它将继续在大型对象堆上,并可能消除您从中获得的任何优势使用System.Text.Json。 (也许我理解错了,每个textLine 不是很大?)您是从本地文件、HTTP 响应还是其他文件中读取 JSON?
  • 如果你绝对需要最小化内存压力,你可以看看微软如何实现Deserialize(string json, Type returnType, JsonSerializerOptions options = null)here
  • 看起来您可以使用附加参数 int start, int length 创建您自己的代码版本,并将这些参数传递给 AsSpan(string, int, int)。您还需要来自JsonReaderHelper 的几种方法的您自己的版本。不确定是否值得。

标签: c# json .net-core json-deserialization system.text.json


【解决方案1】:

这会一样吗?只是阅读您的代码,看起来它会做同样的事情......

public Data GetData(string textLine)
{
    var split = textLine.Split(new char[] {':'});
    var data = JsonSerializer.DeserializeObject<Data>(split[1]);
    return data;
}

【讨论】:

  • 好收获,@Klaycon
  • 抱歉回复晚了。这将完成这项工作,但这正是我最初试图避免的。 textLine.Split(new char[] {':'}); 将为每一行分配一个数组(还有一个数组,因为你有 new char[] {':'} 并且有很多行要处理)。
  • @Mike 没错,但它们都是局部变量,应该很快被 GC 处理。内存使用量应该一直很小。我会试一试,但我敢打赌你不会有任何严重的记忆问题。
  • 您正在分配另外两个字符串。如果使用span,则不需要分配。
猜你喜欢
  • 2020-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-09
  • 2021-10-01
  • 1970-01-01
  • 2020-06-23
相关资源
最近更新 更多