Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON Newtonsoft C# Deserialize List of Objects of Different Types

I need to implement remote connectivity for an existing reporting interface, which requires serialisation and de-serialisation of the data classes. Here is a simplified version of the classes and interfaces:

    public interface IBase
    {
        string Name { get; }
    }

    public interface IDerived1
    {
        int Value { get; }
    }

    public interface IDerived2
    {
        bool Value { get; }
    }

    public class Base : IBase
    {
        public string Name { get; protected set; }
    }

    public class Derived1 : Base, IDerived1
    {
        public int Value { get; protected set; }
    }

    public class Derived2 : Base, IDerived2
    {
        public bool Value { get; protected set; }
    }

As a input parameter I get

IEnumerable<IBase> reportingData

So this collection may contain any number and combination of instances of 'Derived1' and 'Derived2'. I then serialise the collection like this:

string serialisedReportingData = JsonConvert.SerializeObject( reportingData );

Which gives me for example this:

[{"Value":11,"Name":"Product Number"},{"Value":false,"Name":"Output 1 Enabled"}]

Obviously with this data alone, de-serialisation is impossible, as the type of the individual collection entries is not in the JSON. I could for example make the type part of the JSON or provide an additional collection of types for use during de-serialisation.

I have used CustomCreationConverter overloads before to deal with

JsonConvert.DeserializeObject<IEnumerable<Ixxx>>( ... );

type of scenarios, but this only applied to a single interface type inside the IEnumerable. In my example above I have two: IDerived1 and IDerived2.

My questions / issues:

a) I am not sure how a CustomCreationConverter could be written that deals with more than one interface type and I don't know how to get the type into this.

b) I would love your suggestions on how to implement a solution that would give me the same de-serialisation output as the 'IEnumerable reportingData' I received as input.

I would much appreciate a working code example, where possible.

Many thanks in advance, Christian

like image 584
Christian Avatar asked Sep 05 '17 14:09

Christian


People also ask

What is Newtonsoft JSON in C#?

The Newtonsoft. JSON namespace provides classes that are used to implement the core services of the framework. It provides methods for converting between . NET types and JSON types.

Is Newtonsoft JSON obsolete?

Newtonsoft. Json package is not provided by RestSharp, is marked as obsolete on NuGet, and no longer supported by its creator.

How do I use Newtonsoft JSON?

Use the Newtonsoft. Json; To build and run the app, press F5 or select Debug > Start Debugging. Select the Click Me button to see the contents of the TextBlock object replaced with JSON text.

Is JSON used in C#?

Today, JSON is one of the main formats for representing complex structures and data exchange. Therefore, all major programming languages have built-in support for working with it. C# is no exception.


1 Answers

Update: (inspired by the comment from dbc)

You should use a SerializationBinder when deserializing with type names. See here for the KnownTypesBinder. (Newtonsoft.Json Version greater 10 is needed)

First, if you want to set your properties you have to make them public. Then you can use a JsonSerializerSettings to Serialize/Deserialize.

List<IBase> loList = new List<IBase>();
loList.Add(new Base() { Name = "Base" });
loList.Add(new Derived1() { Name = "Derived1", Value = 3 });
loList.Add(new Derived2() { Name = "Derived2", Value = true });

KnownTypesBinder loKnownTypesBinder = new KnownTypesBinder()
{
    KnownTypes = new List<Type> { typeof(Base), typeof(Derived1), typeof(Derived2) }
};

IEnumerable<IBase> reportingData = loList.AsEnumerable();
JsonSerializerSettings loJsonSerializerSettings = new JsonSerializerSettings()
{
    TypeNameHandling = TypeNameHandling.Objects,
    SerializationBinder = loKnownTypesBinder
};

string lsOut = JsonConvert.SerializeObject(reportingData, loJsonSerializerSettings);
reportingData = JsonConvert.DeserializeObject<IEnumerable<IBase>>(lsOut, loJsonSerializerSettings);

If you use the JsonSerializerSettingslike that, the type information will be include in the json string.

[{
        "$type": "Base",
        "Name": "Base"
    }, {
        "$type": "Derived1",
        "Value": 3,
        "Name": "Derived1"
    }, {
        "$type": "Derived2",
        "Value": true,
        "Name": "Derived2"
    }
]
like image 87
PinBack Avatar answered Sep 28 '22 09:09

PinBack