序列化器上的字符串Intern.Deserialize <T>()

Bas*_*aro 3 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"
    }]
}]
Run Code Online (Sandbox Code Playgroud)

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

也可能看起来像“代码”可能重复,但这对每个人来说都是唯一的。基本上是同一对象的多个标识符。

dbc*_*dbc 6

If you know your 4 standard strings in advance, you can intern them with String.Intern() (or just declare them as string literals somewhere -- that does the job) then use the following custom JsonConverter to convert all JSON string literals to their interned value if one is found:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

This can be applied globally via serializer settings:

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

You can also apply it to the specific string collection using JsonPropertyAttribute.ItemConverterType:

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

If you don't know the 4 strings in advance, you can create a converter that interns the strings as they are read:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

更新资料

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

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

    public string code { get; set; }
}
Run Code Online (Sandbox Code Playgroud)