代码之家  ›  专栏  ›  技术社区  ›  mark

为什么我无聊的Newtonsoft。Json反序列化代码不起作用?

  •  0
  • mark  · 技术社区  · 4 年前

    我有以下习惯 JsonConverter :

    using Microsoft.CodeAnalysis.Text;
    using Newtonsoft.Json;
    using System;
    
    namespace CSTool.Json
    {
        public class TextSpanJsonConverter : JsonConverter
        {
            public override bool CanConvert(Type objectType) => objectType == typeof(TextSpan);
    
            public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
            {
                var str = reader.ReadAsString();
                var delim = str.IndexOf('.');
                var start = int.Parse(str.AsSpan(1, delim - 1));
                var end = int.Parse(str.AsSpan(delim + 2, str.Length - delim - 3));
                return TextSpan.FromBounds(start, end);
            }
    
            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
            {
                writer.WriteValue(value.ToString());
            }
        }
    }
    

    它应该有助于(反)序列化以下类:

    using CSTool.Json;
    using Microsoft.CodeAnalysis;
    using Microsoft.CodeAnalysis.Text;
    using Newtonsoft.Json;
    
    namespace CSTool.ObjectModel
    {
        public class RefLocCacheItem
        {
            public string FilePath { get; private set; }
            [JsonConverter(typeof(TextSpanJsonConverter))]
            public TextSpan TextSpan { get; private set; }
            [JsonConverter(typeof(LinePositionSpanJsonConverter))]
            public LinePositionSpan LinePositionSpan { get; private set; }
    
            public RefLocCacheItem()
            {
            }
            public RefLocCacheItem(Location o) : this(o.SourceTree.FilePath, o.SourceSpan, o.GetLineSpan().Span)
            {
            }
            public RefLocCacheItem(string filePath, TextSpan textSpan, LinePositionSpan linePositionSpan)
            {
                FilePath = filePath;
                TextSpan = textSpan;
                LinePositionSpan = linePositionSpan;
            }
        }
    }
    

    反序列化代码为:

    cached = JsonConvert.DeserializeObject<Dictionary<uint, List<RefLocCacheItem>>>(File.ReadAllText(cacheFile));
    

    相应的序列化代码为:

    File.WriteAllText(cacheFile, JsonConvert.SerializeObject(cached, Newtonsoft.Json.Formatting.Indented));
    

    下面是一个json文件示例:

    {
      "100666494": [],
      "100666517": [],
      "67111627": [
        {
          "FilePath": "c:\xyz\\tip\\MySourceFile.cs",
          "TextSpan": "[105331..105379)",
          "LinePositionSpan": "(2379,51)-(2379,99)"
        }
      ],
      "67111628": [
        {
          "FilePath": "c:\xyz\\tip\\MySourceFile.cs",
          "TextSpan": "[136762..136795)",
          "LinePositionSpan": "(2953,30)-(2953,63)"
        }
      ],
      "100666534": []
    }
    

    所以,正如你所看到的,序列化工作得很好。然而,反序列化代码从不调用转换器的 ReadJson 功能。事实上,它根本不起作用!没有失败,但返回的字典包含 RefLocCacheItem s with null 文件路径和空文本跨度:

    enter image description here

    我用的是Json。过去上网很多次,我不明白我现在做错了什么。

    我使用的是最新版本13.0.1,但我检查了一些旧版本——同样的事情。所以,这是我的错,但在哪里?

    澄清编辑

    这个 FilePath 属性未反序列化。这与转换器无关。和转换器- ReadJson 方法甚至没有被调用!

    0 回复  |  直到 3 年前
        1
  •  2
  •   Brian Rogers    4 年前

    问题是你的属性有私有设置器。因此,Json。Net将把它们视为只读。您可以将setter设置为公共,或者,如果您希望将setter保持为私有,可以添加一个 [JsonProperty] 属性来告诉Json。Net表示可以使用私有setter:

    [JsonProperty]
    public string FilePath { get; private set; }
    
    [JsonProperty, JsonConverter(typeof(TextSpanJsonConverter))]
    public TextSpan TextSpan { get; private set; }