Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
397 views
in Technique[技术] by (71.8m points)

c# - Efficiently get full json string in JsonConverter.ReadJson()

How can I efficiently get full json string in JsonConverter.ReadJson() ?

I can do:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
      var json = JObject.Load(reader).ToString(Formatting.None);

However that seems very inefficient as I serialize and deserialize for no reason

Any better way ?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

ReadJson() must fully parse the JSON being read so that the JSON is confirmed to be well-formed and the JsonReader is correctly positioned at the end of the current value upon exit. However, it is not necessary to load the entire JSON into an intermediate JObject hierarchy simply to re-convert it to a JSON string. Instead, you may be able to get better performance by using JRaw.Create():

var json = JRaw.Create(reader).ToString();

As can be seen in the reference source, this method streams directly from the incoming JsonReader to a StringWriter - without loading into an intermediate JToken hierarchy and re-serializing - by using JsonWriter.WriteToken(JsonReader):

public static JRaw Create(JsonReader reader)
{
    using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture))
    using (JsonTextWriter jsonWriter = new JsonTextWriter(sw))
    {
        jsonWriter.WriteToken(reader);

        return new JRaw(sw.ToString());
    }
}

The resulting JRaw simply encapsulates that string in its Value. (Of course, there is no guarantee that the resulting JSON represents an object, only that it represents well-formed JSON.)

Note that JsonTextReader will automatically recognize and parse dates and times in common formats as DateTime objects, and also parse floating point values as double. If you need the "most literal" JSON string you may want to suppress DateTime recognition and/or parse floating point values as decimal. The following extension method, modeled on JRaw.Create(), does the job:

public static string ReadOuterJson(this JsonReader reader, Formatting formatting = Formatting.None, DateParseHandling? dateParseHandling = null, FloatParseHandling? floatParseHandling = null)
{
    // If you would prefer a null JSON value to return an empty string, remove this line:
    if (reader.TokenType == JsonToken.Null)
        return null;
    var oldDateParseHandling = reader.DateParseHandling;
    var oldFloatParseHandling = reader.FloatParseHandling;
    try
    {
        if (dateParseHandling != null)
            reader.DateParseHandling = dateParseHandling.Value;
        if (floatParseHandling != null)
            reader.FloatParseHandling = floatParseHandling.Value;
        using (var sw = new StringWriter(CultureInfo.InvariantCulture))
        using (var jsonWriter = new JsonTextWriter(sw) { Formatting = formatting })
        {
            jsonWriter.WriteToken(reader);
            return sw.ToString();
        }
    }
    finally
    {
        reader.DateParseHandling = oldDateParseHandling;
        reader.FloatParseHandling = oldFloatParseHandling;
    }
}

And then call it like, e.g.:

var json = reader.ReadOuterJson(dateParseHandling: DateParseHandling.None);

For details on why this may be necessary, see:


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...