Newtonsoft JsonSerializer没有设置正确的类型

时间:2017-06-20 09:53:31

标签: c# json.net

我有一个JsonSerializer的自定义包装器,它看起来像这样:

public class MySerializer
{
    JsonSerializer serializer;

    public MySerializer()
    {
        serializer = new JsonSerializer
        {
            TypeNameHandling = TypeNameHandling.Auto,
            DefaultValueHandling = DefaultValueHandling.Ignore,
            NullValueHandling = NullValueHandling.Ignore,
            ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
            ContractResolver = new DefaultContractResolver()
        };
    }

    public byte[] Serialize<T>(T value)
    {
        using (MemoryStream memoryStream = new MemoryStream())
        {
            using (var streamWriter = new StreamWriter(memoryStream, Encoding.UTF8))
                serializer.Serialize(new JsonTextWriter(streamWriter), value);
            return memoryStream.ToArray();
        }
    }

    public T Deserialize<T>(byte[] serialized)
    {
        using (MemoryStream memoryStream = new MemoryStream(serialized))
        {
            using (var streamReader = new StreamReader(memoryStream, Encoding.UTF8))
                return serializer.Deserialize<T>( new JsonTextReader(streamReader));
        }
    }
}

由于项目的限制,它通常可以正常使用确实需要来使用JsonSerializer。我不是在寻找任何其他序列化器。

我要序列化/反序列化的类看起来像这样:

public class Person
{
    public House LivingArrangement { get; set; } = new TreeHouse();
}

public class House
{
    public int NumberOfBeds { get; set; }
    public virtual bool IsInTree => false; // just to show the issue
}

public class TreeHouse : House
{
    public override bool IsInTree => true; // just to show the issue
}

在现实世界中,它要复杂得多,但这只是为了说明问题。请注意,如果未设置任何其他内容,则Person每个TreeHouse都会生成TreeHouse。这非常重要,由于我的项目中的其他限制,无法更改。在启动类时,必须将类型设置为null。它不能是TreeHouse

问题是,当反序列化类时,类型为House,即使我明确地将其设置为 [TestMethod] public void Serialization_Test() { var item = new Person(); item.LivingArrangement = new House(); // This person lives in a house. item.LivingArrangement.NumberOfBeds = 2; var serializer = new MySerializer(); var serializedItem = serializer.Serialize(item); var deserializedItem = serializer.Deserialize<Person>(serializedItem); Console.WriteLine(deserializedItem.LivingArrangement.GetType()); // Output: UnitTestProject1.TreeHouse // Works fine! Assert.IsTrue(item.LivingArrangement.NumberOfBeds == 2); // The assert fails. Assert.IsFalse(deserializedItem.LivingArrangement.IsInTree); // The assert fails. Assert.AreEqual(deserializedItem.LivingArrangement.GetType(), typeof(House)); } 。请参阅下面的测试。

JsonSerializer

为什么TreeHouse保留House而不是发起{{1}}的新实例?我该如何修复它,但仍然使用JsonSerializer?

1 个答案:

答案 0 :(得分:1)

您必须设置其他属性ObjectCreationHandling

serializer = new JsonSerializer
{
    TypeNameHandling = TypeNameHandling.Auto,
    ObjectCreationHandling = ObjectCreationHandling.Replace,
    DefaultValueHandling = DefaultValueHandling.Ignore,
    NullValueHandling = NullValueHandling.Ignore,
    ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
    ContractResolver = new DefaultContractResolver()
};

现在您在json中有更多信息。 如果您将TreeHouse设置为LivingArrangement,则您的JSON-String中包含类型信息($type)。