C# Newtonsoft JsonSerializer未设置正确的类型

C# Newtonsoft JsonSerializer未设置正确的类型,c#,json.net,C#,Json.net,我有一个自定义包装,其外观如下所示: public class MySerializer { JsonSerializer serializer; public MySerializer() { serializer = new JsonSerializer { TypeNameHandling = TypeNameHandling.Auto, DefaultValueHandling =

我有一个自定义包装,其外观如下所示:

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));
        }
    }
}
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
}
在现实世界中要复杂得多,但这只是为了说明问题。请注意,如果没有其他设置,每个人都住在树屋中。这是非常重要的,不能因为我的项目中的其他限制而更改。初始化类时,必须将类型设置为TreeHouse。它不能为空

问题是,当类被反序列化时,类型是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的新实例?如何修复它,但仍然使用JsonSerializer?

您必须设置一个附加属性ObjectCreationHandling:

现在,json中有了更多信息。 如果您将树屋设置为LivingArrange,那么您的JSON字符串在$type中包含类型信息

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