序列化和反序列化不适用于字典作为支持字段

Serialization & Deserialization wont work with Dictionary as Backing field

当字典隐藏在 属性 后面的支持字段中时,我 运行 遇到了一个奇怪的问题 Serialization/Deserialization 字典。

这是 Fiddle: https://dotnetfiddle.net/RFZEur

最终结果:

public class SanityChecks
{
    private readonly ITestOutputHelper _testOutputHelper;
    public SanityChecks(ITestOutputHelper testOutputHelper)
    {
        _testOutputHelper = testOutputHelper;
    }
    public class TestClass 
    {
        [JsonIgnore]
        public Dictionary<int,string> _prvList = new Dictionary<int, string>();
        public IEnumerable<string> ListValues
        {
            get => _prvList.Select(p=> p.Value).ToList();
            set
            {
                var valArr = value.ToArray();
                for (var x = 0; x < valArr.Length; x++)
                {
                    _prvList.Add(x,valArr[x]);
                }
            }
        }
    }
    [Fact]
    public void SanityCheck_CanDeserialize()
    {
        var assumption = "{\"ListValues\":[\"TestValue\",\"AAA\"]}";
        var actual = JsonConvert.DeserializeObject<TestClass>(assumption);
        Assert.Equal(2, actual._prvList.Count());
        Assert.Equal(2, actual.ListValues.Count());
    }
    [Fact]
    public void SanityCheck_CanSerialize()
    {
        var assumption = new TestClass() { ListValues = new[] { "TestValue", "AAA" } };
        var actualSerialized = JsonConvert.SerializeObject(assumption);
        _testOutputHelper.WriteLine(actualSerialized);
        Assert.Equal("{\"ListValues\":[\"TestValue\",\"AAA\"]}", actualSerialized);
    }
    [Fact]
    public void SanityCheck_CanDeserializeFromSerialized()
    {
        var assumption = new TestClass() { ListValues = new[] { "TestValue", "AAA" } };
        var actualSerialized = JsonConvert.SerializeObject(assumption);
        _testOutputHelper.WriteLine(actualSerialized);
        var actualDeserialized = JsonConvert.DeserializeObject<TestClass>(actualSerialized);
        Assert.Equal(2, actualDeserialized._prvList.Count());
        var actualDeserializedSerialized = JsonConvert.SerializeObject(actualDeserialized);
        _testOutputHelper.WriteLine(actualDeserializedSerialized);
        Assert.Equal(actualSerialized, actualDeserializedSerialized);
    }
}

如果您对如何检索此结果有一些建议,我愿意。我正在使用 XUnit 进行测试,但是 fiddle 可以快速执行下面的测试,并稍作修改使其成为控制台应用程序。

我已经尝试将 ISerializable 的实现应用到对象中,但是我 运行 遇到了同样的问题。

值得注意的奇怪之处:IEnumerable 中 Get 子句的 删除 导致反序列化工作(序列化不再工作)

编辑: 为了更加清楚,我需要将 int、string 对的映射序列化为字符串列表,并且我需要将相同的序列化版本反序列化为 int、string 对的集合。

对于Fiddle:应该没有异常抛出 对于 XUnit:所有测试都应该通过。

反序列化后ListValues枚举为空的原因有以下几个因素:

  1. 默认情况下,Json.Net 将在反序列化过程中重用现有对象值,而不是创建新值。因此,对于 ListValues 之类的属性,它将首先调用访问器,然后找到一个现有列表,然后从 JSON.
  2. 继续填充它
  3. ListValues 的访问器并不是每次都return 相同的列表实例;它总是从 _prvList 支持字段创建一个新实例。

因此,这是反序列化过程中发生的事情:

  1. 序列化程序调用 ListValues 访问器,它 return 是从字典创建的新空列表。
  2. 序列化程序从 JSON.
  3. 填充该列表
  4. 已填充的列表被丢弃(序列化程序假定 TestClass 实例已经引用了该列表,因此它永远不会调用修改器)。
  5. 当测试稍后调用 ListValues 访问器时,它 return 再次从字典创建一个新的空列表。

您可以通过将 ObjectCreationHandling 设置为 Replace 来更改序列化程序的行为。在反序列化期间应用此设置可以让您的测试通过。 Fiddle here.