Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用Newtonsoft反序列化JSON时缓存/插入对象键_C#_Json_String_Json.net_Deserialization - Fatal编程技术网

C# 使用Newtonsoft反序列化JSON时缓存/插入对象键

C# 使用Newtonsoft反序列化JSON时缓存/插入对象键,c#,json,string,json.net,deserialization,C#,Json,String,Json.net,Deserialization,我有一个API方法,它将一个DB中约100k行加载到内存中,每一行都包含一个JSON字符串。对于每个请求,JSON对象结构在所有行中都是相同的(相同的对象键),尽管我不会提前知道这一点 目前,我正在为每一行调用JObject.Parse(row.Json),以获得一个JObject。当我检查堆时,我可以看到每个对象键字符串的重复条目。因此,如果我在每一行的JSON中都有对象键id,并且我有100k行,那么我在内存中会看到这个字符串的100k个实例 我想缓存这些对象键(或者可能是String.In

我有一个API方法,它将一个DB中约100k行加载到内存中,每一行都包含一个JSON字符串。对于每个请求,JSON对象结构在所有行中都是相同的(相同的对象键),尽管我不会提前知道这一点

目前,我正在为每一行调用
JObject.Parse(row.Json)
,以获得一个JObject。当我检查堆时,我可以看到每个对象键字符串的重复条目。因此,如果我在每一行的JSON中都有对象键
id
,并且我有100k行,那么我在内存中会看到这个字符串的100k个实例

我想缓存这些对象键(或者可能是
String.Intern()
,具体取决于生命周期),并重用这些
JObject
s中的字符串。我可以看到,使用
JsonConvert.DeserializeObject()
我可以提供一个自定义转换器,但是它们允许您修改JSON值,而不是键


注意:我必须一次将所有100k行存储在内存中,因为我稍后会运行一个algo,该algo需要同时执行所有操作。

如果您知道JSON的结构,您可以创建一个包含最常见字段的类。这将节省相当多的空间

class RowData
{
    [JsonProperty("id")]
    public int Id { get; set; }
    [JsonProperty("anyOtherFixedField")]
    public string OtherField{ get; set; }
    [JsonExtensionData]
    public IDictionary<string, JToken> ExtraProperties {get; set;}
}
类行数据
{
[JsonProperty(“id”)]
公共int Id{get;set;}
[JsonProperty(“任何其他固定字段”)]
公共字符串OtherField{get;set;}
[JsonExtensionData]
公共IDictionary外部属性{get;set;}
}
具有属性的字段在堆上根本没有字符串


JSON中没有相应属性的任何字段都将进入
ExtraProperties
字典。

如果您知道JSON的结构,您可以创建一个包含最常见字段的类。这将节省相当多的空间

class RowData
{
    [JsonProperty("id")]
    public int Id { get; set; }
    [JsonProperty("anyOtherFixedField")]
    public string OtherField{ get; set; }
    [JsonExtensionData]
    public IDictionary<string, JToken> ExtraProperties {get; set;}
}
类行数据
{
[JsonProperty(“id”)]
公共int Id{get;set;}
[JsonProperty(“任何其他固定字段”)]
公共字符串OtherField{get;set;}
[JsonExtensionData]
公共IDictionary外部属性{get;set;}
}
具有属性的字段在堆上根本没有字符串


JSON中没有相应属性的任何字段都将进入
ExtraProperties
字典。

似乎没有一个好方法可以钩住默认的JObject反序列化

基于提供的,我制作了一个自定义转换器,它创建了一个
JValue
/
JObject
/
JArray
,而不是
ExpandoObject
。在转换器的生命周期内,所有对象键都被缓存和重用

要使用此转换器,必须指定要反序列化为
JToken
JObject
JArray
。 如果未指定目标类型,则不会使用此转换器

var data = JsonConvert.DeserializeObject<JToken>(json, new NameCachingJObjectConverter());
var data=JsonConvert.DeserializeObject(json,新名称cachingjObjectConverter());
以及实施

public class NameCachingJObjectConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // can write is set to false
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return ReadValue(reader);
    }

    private JToken ReadValue(JsonReader reader)
    {
        if (!MoveToContent(reader))
        {
            throw new Exception("Unexpected end of content");
        }

        switch (reader.TokenType)
        {
            case JsonToken.StartObject:
                return ReadObject(reader);
            case JsonToken.StartArray:
                return ReadList(reader);
            default:
                if (IsPrimitiveToken(reader.TokenType))
                {
                    return new JValue(reader.Value);
                }

                throw new Exception("Unexpected token when converting object: {reader.TokenType}");
        }
    }

    private static bool IsPrimitiveToken(JsonToken token)
    {
        switch (token)
        {
            case JsonToken.Integer:
            case JsonToken.Float:
            case JsonToken.String:
            case JsonToken.Boolean:
            case JsonToken.Undefined:
            case JsonToken.Null:
            case JsonToken.Date:
            case JsonToken.Bytes:
                return true;
            default:
                return false;
        }
    }

    private static bool MoveToContent(JsonReader reader)
    {
        JsonToken t = reader.TokenType;
        while (t == JsonToken.None || t == JsonToken.Comment)
        {
            if (!reader.Read())
            {
                return false;
            }
            t = reader.TokenType;
        }
        return true;
    }

    private JArray ReadList(JsonReader reader)
    {
        var list = new JArray();

        while (reader.Read())
        {
            switch (reader.TokenType)
            {
                case JsonToken.Comment:
                    break;
                default:
                    object v = ReadValue(reader);

                    list.Add(v);
                    break;
                case JsonToken.EndArray:
                    return list;
            }
        }

        throw new Exception("Unexpected end when reading JObject.");
    }

    private JToken ReadObject(JsonReader reader)
    {
        var expandoObject = new JObject();

        while (reader.Read())
        {
            switch (reader.TokenType)
            {
                case JsonToken.PropertyName:
                    string propertyName = GetCachedName(reader.Value.ToString());

                    if (!reader.Read())
                    {
                        throw new Exception("Unexpected end when reading JObject.");
                    }

                    var v = ReadValue(reader);

                    expandoObject[propertyName] = v;
                    break;
                case JsonToken.Comment:
                    break;
                case JsonToken.EndObject:
                    return expandoObject;
            }
        }

        throw new Exception("Unexpected end when reading ExpandoObject.");
    }

    /// <summary>
    /// Determines whether this instance can convert the specified object type.
    /// </summary>
    /// <param name="objectType">Type of the object.</param>
    /// <returns>
    ///     <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
    /// </returns>
    public override bool CanConvert(Type objectType)
    {
        return (typeof(JToken).IsAssignableFrom(objectType));
    }

    /// <summary>
    /// Gets a value indicating whether this <see cref="JsonConverter"/> can write JSON.
    /// </summary>
    /// <value>
    ///     <c>true</c> if this <see cref="JsonConverter"/> can write JSON; otherwise, <c>false</c>.
    /// </value>
    public override bool CanWrite => false;



    private string GetCachedName(string value)
    {
        string ret;
        if (!cache.TryGetValue(value, out ret))
        {
            cache[value] = value;
            ret = value;
        }
        return ret;
    }
    private readonly Dictionary<string, string> cache = new Dictionary<string, string>();
}
公共类名称cachingjobjectconverter:JsonConverter
{
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
//can write设置为false
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
返回ReadValue(reader);
}
私有JToken ReadValue(JsonReader)
{
如果(!移动内容(读卡器))
{
抛出新异常(“内容意外结束”);
}
开关(reader.TokenType)
{
案例JsonToken.StartObject:
返回ReadObject(reader);
案例JsonToken.StartArray:
返回ReadList(reader);
违约:
if(IsPrimitiveToken(reader.TokenType))
{
返回新的JValue(reader.Value);
}
抛出新异常(“转换对象时出现意外标记:{reader.TokenType}”);
}
}
专用静态布尔IsPrimitiveToken(JsonToken令牌)
{
交换机(令牌)
{
案例JsonToken.Integer:
case JsonToken.Float:
case JsonToken.String:
案例JsonToken.Boolean:
案例JsonToken。未定义:
案例JsonToken.Null:
案例JsonToken。日期:
案例JsonToken.Bytes:
返回true;
违约:
返回false;
}
}
私有静态布尔移动内容(JsonReader)
{
JsonToken t=reader.TokenType;
while(t==JsonToken.None | | t==JsonToken.Comment)
{
如果(!reader.Read())
{
返回false;
}
t=reader.TokenType;
}
返回true;
}
私有JArray读取列表(JsonReader)
{
var list=new JArray();
while(reader.Read())
{
开关(reader.TokenType)
{
案例JsonToken。评论:
打破
违约:
对象v=读取值(读取器);
增加(五)项;
打破
案例JsonToken.EndArray:
退货清单;
}
}
抛出新异常(“读取JObject时意外结束”);
}
私有JToken ReadObject(JsonReader)
{
var expandoObject=new JObject();
while(reader.Read())
{
开关(reader.TokenType)
{
案例JsonToken.PropertyName:
string propertyName=GetCachedName(reader.Value.ToString());
如果(!reader.Read())
{
抛出新异常(“读取JObject时意外结束”);
}
var v=读取值(读取器);
扩展对象[属性]