c# - serializer.Deserialize<T>() 上的字符串实习生

标签 c# json json.net string-interning

我目前正在使用 json.net 反序列化一个字符串,该字符串是中等大小的对象集合。总共约 7000 项。

每个项目都有一个由 4 个相同字符串组成的重复组,在内存分析中,这会根据嵌套等创建大约 40,000 个引用。

有没有办法让序列化器对每个相同的字符串使用相同的引用?

示例 Json:

  [{
    "name":"jon bones",
    "groups":[{
        "groupName":"Region",
        "code":"1"
    },{
        "groupName":"Class",
        "code":"4"
    }]
},
{
    "name":"Swan moans",
    "groups":[{
        "groupName":"Region",
        "code":"12"
    },{
        "groupName":"Class",
        "code":"1"
    }]
}]

添加示例。如您所见,groupName 值在几乎所有对象上重复出现。只是相关代码发生了变化。这不是一个大问题,但随着数据集的增长,我宁愿不要增加太多分配。

此外,“代码”似乎可能会重复,但对每个人来说都是独一无二的。基本上是同一对象的多个标识符。

最佳答案

如果你事先知道你的 4 个标准字符串,你可以使用 String.Intern() 来实习它们(或者只是在某处将它们声明为字符串文字 - 完成工作)然后使用以下 custom JsonConverter如果找到一个,将所有 JSON 字符串文字转换为其内部值:

public class InternedStringConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(string);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var s = reader.TokenType == JsonToken.String ? (string)reader.Value : (string)JToken.Load(reader); // Check is in case the value is a non-string literal such as an integer.
        return String.IsInterned(s) ?? s;
    }

    public override bool CanWrite { get { return false; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

这可以通过序列化器设置全局应用:

        var settings = new JsonSerializerSettings { Converters = new [] { new InternedStringConverter() } };
        var root = JsonConvert.DeserializeObject<RootObject>(jsonString, settings);

您还可以使用 JsonPropertyAttribute.ItemConverterType 将其应用于特定的字符串集合:

public class Group
{
    [JsonProperty(ItemConverterType = typeof(InternedStringConverter))]
    public List<string> StandardStrings { get; set; }
}

如果您事先不知道这 4 个字符串,您可以创建一个转换器,在读取字符串时对其进行实习:

public class AutoInterningStringConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        // CanConvert is not called when a converter is applied directly to a property.
        throw new NotImplementedException("AutoInterningStringConverter should not be used globally");
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var s = reader.TokenType == JsonToken.String ? (string)reader.Value : (string)JToken.Load(reader); // Check is in case the value is a non-string literal such as an integer.
        return String.Intern(s);
    }

    public override bool CanWrite { get { return false; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

但是,我强烈建议不要在全局范围内使用它,因为您最终可能会向内部字符串表中添加大量字符串。相反,将它应用于您确信包含少量唯一字符串的重复项的特定字符串集合:

public class Group
{
    [JsonProperty(ItemConverterType = typeof(AutoInterningStringConverter))]
    public List<string> StandardStrings { get; set; }
}

更新

从您更新的问题中,我看到您有具有标准值的字符串属性,而不是具有标准值的字符串集合。因此你会使用 [JsonConverter(typeof(AutoInterningStringConverter))]在每个:

public class Group
{
    [JsonConverter(typeof(AutoInterningStringConverter))]
    public string groupName { get; set; }

    public string code { get; set; }
}

关于c# - serializer.Deserialize<T>() 上的字符串实习生,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34904015/

相关文章:

c# - 如何获取带有名称和任何扩展名的图像?

c# - 是否可以为 WebService 进行设置安装?

php - REST API,成功和错误的数据返回方式

javascript - 使用 Node 本地化

c# - Json.NET - 自定义转换器 - 字符串到 Int

ios - 如何使用 $ref 和 $id 在 RestKit 中使用循环引用

C#:wpf 将组合框项添加到多个组合框

c# - WIX-- 自动更新

javascript - jquery json加载两个变量

json.net - JsonConverter 的 ReadJson 方法中的existingValue 参数有何用途?