1

Using Newtonsoft (with TypeNameHandling.All), if I serialize a List<Animal> that includes a <Cat> and a <Dog>, when I deserialize the string back into a List<Animal>, they lose their inheritance and become just <Animals>.

Is there a way for Newtonsoft to preserve the subclasses as they get deserialized back into a List of their parent class?

Here are the objects:

 public class Zoo
    {
        public List<Animal> Animals;

        public Zoo()
        {
            Animals = new List<Animal>();
        }
    }
    public class Animal
    {

    }

    public class Dog : Animal
    {

    }

    public class Cat : Animal
    {

    }
}

Here's the test:

static void Main(string[] args)
        {
            var zoo = new Zoo();
            var dog = new Dog();
            var cat = new Cat();
            zoo.Animals.Add(dog);
            zoo.Animals.Add(cat);

            var json = JsonConvert.SerializeObject(zoo, Formatting.None,
                new JsonSerializerSettings
                {
                    TypeNameHandling = TypeNameHandling.All
                });

            var newZoo = JsonConvert.DeserializeObject<Zoo>(json);
        }

Here's what the original Zoo.Animal list looks like (notice the Dog and Cat types):

Dog and Cat classes are visible

Now, once it's serialized, we can see the subclasses are included correctly. Should be enough information to deserialize it back into a similar object:

{
    "$type": "Sample.Sandbox.Zoo, Sample.Sandbox",
    "Animals": {
        "$type": "System.Collections.Generic.List`1[[Sample.Sandbox.Animal, Sample.Sandbox]], System.Private.CoreLib",
        "$values": [
            {
                "$type": "Sample.Sandbox.Dog, Sample.Sandbox"
            },
            {
                "$type": "Sample.Sandbox.Cat, Sample.Sandbox"
            }
        ]
    }
}

But when it gets deserialized, the Dog and Cat are gone. They are just Animals now: Improperly deserialized list

Is there a way for Newtonsoft to properly Deserialize the JSON and maintain the subclass types?

Many thanks for any tips.

Hairgami_Master
  • 5,429
  • 10
  • 45
  • 66
  • 2
    You didn't pass `TypeNameHandling.All` when deserializing. For security reasons it's opt-in, so you need to use it for both serialization and deserialization. See [JSON deserialization of derived types](https://stackoverflow.com/q/40499272/3744182), which seems to be a duplicate. Agree? – dbc Dec 08 '20 at 04:48

1 Answers1

1

You need to add settings on both the serialiser and deserialiser.

try this:

JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
var json = JsonConvert.SerializeObject(zoo,settings);    
var newZoo = JsonConvert.DeserializeObject<Zoo>(json,settings);
    
foreach (var currentAnimal in newZoo.Animals)
{ 
   Console.WriteLine(currentAnimal.GetType().Name);
}

Should print out: Dog Cat

Richard
  • 874
  • 2
  • 9
  • 23