2017-06-20 40 views
0

我有JsonSerializer一個定製的包裝,看起來是這樣的:Newtonsoft 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一個新的實例?我該如何解決它,但仍然使用JsonSerializer?

回答

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字符串在($type)中有類型信息。