Десериализация словаря с производными типами с использованием библиотеки Json от NewtonSoft

#json #serialization #json.net

#json #сериализация #json.net

Вопрос:

Учитывая следующую структуру классов, которая включает в себя словарь производных объектов, как я могу сериализовать и десериализовать с помощью библиотеки Json от NewtonSoft? При десериализации я получаю исключение. Похоже, у него возникли проблемы с восстановлением словаря.

 [JsonObject(MemberSerialization.OptIn)]
public class GameObject
{
    [JsonProperty]
    public string Id { get; set; }

    [JsonProperty]
    public string Name { get; set; }

    [JsonProperty]
    public ConcurrentDictionary<string, Component> Components;

    public GameObject()
    {
        Components = new ConcurrentDictionary<string, Component>();
    }

}

[JsonObject(MemberSerialization.OptIn)]
public class Component
{
    [JsonIgnore] // Ignore circular reference
    public GameObject GameObject { get; set; }

    public Component()
    {
    }
}

[JsonObject(MemberSerialization.OptIn)]
public class TestComponent : Component
{
    [JsonProperty]
    public int MyProperty { get; set; }

    public TestComponent()
    {
    }
}




var originalJson = JsonConvert.SerializeObject(srcObject, Formatting.None, 
    new JsonSerializerSettings
                {
                    TypeNameHandling = TypeNameHandling.All,
                    TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple
                });

var newObject = JsonConvert.DeserializeObject<GameObject>(originalJson, 
    new JsonSerializerSettings()
                {
                    TypeNameHandling = TypeNameHandling.All,
                    TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple
                });
  

Исключение при вызове DeserializeObject:

 System.Reflection.TargetInvocationException was unhandled by user code
  Message=Exception has been thrown by the target of an invocation.
  Source=mscorlib
  StackTrace:
       at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStructamp; sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
       at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
       at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
       at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
       at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
       at Newtonsoft.Json.Serialization.JsonContract.InvokeOnDeserialized(Object o, StreamingContext context) in d:DevelopmentReleasesJsonWorkingSrcNewtonsoft.JsonSerializationJsonContract.cs:line 135
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateDictionary(IWrappedDictionary dictionary, JsonReader reader, JsonDictionaryContract contract, String id) in d:DevelopmentReleasesJsonWorkingSrcNewtonsoft.JsonSerializationJsonSerializerInternalReader.cs:line 638
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateAndPopulateDictionary(JsonReader reader, JsonDictionaryContract contract, String id) in d:DevelopmentReleasesJsonWorkingSrcNewtonsoft.JsonSerializationJsonSerializerInternalReader.cs:line 593
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue) in d:DevelopmentReleasesJsonWorkingSrcNewtonsoft.JsonSerializationJsonSerializerInternalReader.cs:line 387
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue) in d:DevelopmentReleasesJsonWorkingSrcNewtonsoft.JsonSerializationJsonSerializerInternalReader.cs:line 223
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueProperty(JsonReader reader, JsonProperty property, Object target, Boolean gottenCurrentValue, Object currentValue) in d:DevelopmentReleasesJsonWorkingSrcNewtonsoft.JsonSerializationJsonSerializerInternalReader.cs:line 198
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectFromNonDefaultConstructor(JsonReader reader, JsonObjectContract contract, String id) in d:DevelopmentReleasesJsonWorkingSrcNewtonsoft.JsonSerializationJsonSerializerInternalReader.cs:line 876
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateAndPopulateObject(JsonReader reader, JsonObjectContract contract, String id) in d:DevelopmentReleasesJsonWorkingSrcNewtonsoft.JsonSerializationJsonSerializerInternalReader.cs:line 846
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue) in d:DevelopmentReleasesJsonWorkingSrcNewtonsoft.JsonSerializationJsonSerializerInternalReader.cs:line 396
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue) in d:DevelopmentReleasesJsonWorkingSrcNewtonsoft.JsonSerializationJsonSerializerInternalReader.cs:line 223
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueNonProperty(JsonReader reader, Type objectType, JsonContract contract) in d:DevelopmentReleasesJsonWorkingSrcNewtonsoft.JsonSerializationJsonSerializerInternalReader.cs:line 208
       at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType) in d:DevelopmentReleasesJsonWorkingSrcNewtonsoft.JsonSerializationJsonSerializerInternalReader.cs:line 120
       at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType) in d:DevelopmentReleasesJsonWorkingSrcNewtonsoft.JsonJsonSerializer.cs:line 421
       at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType) in d:DevelopmentReleasesJsonWorkingSrcNewtonsoft.JsonJsonSerializer.cs:line 413
       at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings) in d:DevelopmentReleasesJsonWorkingSrcNewtonsoft.JsonJsonConvert.cs:line 721
       at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings) in d:DevelopmentReleasesJsonWorkingSrcNewtonsoft.JsonJsonConvert.cs:line 683
       at MF.Tests.GameServer.ComponentSerializationTests.TestSerializationOfObjectWithComponent() in C: ComponentSerializationTests.cs:line 119
  InnerException: System.NullReferenceException
       Message=Object reference not set to an instance of an object.
       Source=mscorlib
       StackTrace:
            at System.Collections.Concurrent.ConcurrentDictionary`2.InitializeFromCollection(IEnumerable`1 collection)
            at System.Collections.Concurrent.ConcurrentDictionary`2.OnDeserialized(StreamingContext context)
       InnerException:
  

Обновить:

Если изменить ConcurrentDictionary на список или словарь, код работает так, как ожидалось.

Что я делаю не так?

Комментарии:

1. У меня точно такая же проблема… Похоже, есть что-то интересное в сериализации / десериализации параллельного словаря с объектами в нем.