Deserialise IList <Interfaces> in JSON.NET

I have a json that I want Deserialise. It is very easy to deserialize back to the list However, I am working with interfaces and this is what I need deserialisation to end up on:

So let's start with some JSON:

[{"TimeGenerated":"2017-05-30T19:21:06.5331472+10:00","OuterValue":1.08,"Identifier":{"IdentifierName":"BLA","IdentifierNumber":1},"Locale":{"LocaleName":"LOCALE NAME","LocaleType":1,"LocaleNumber":1,"StartTime":"2017-05-30T19:20:00+10:00"},"InnerValue":1.08,"InnerType":0,"InnerId":"InnerI","Type":"MyType","Id":"11111"}]
      

This is data that is serialized on the server side (no problem, of course) and this type of object:

IList<IRootObject>

      

So efficiently, I want to deserialize the other side like:

IList<IRootObject> MyDeserialisedObject = JsonConvert.Deserialise<IList<IRootObject>>(JsonString);

      

Obviously the pickle here is an old interface / abstract type error:

'Could not create an instance of type BLA. Type is an interface or abstract class and cannot be instantiated'

      

Ok, I am creating some custom converters and decorate like this:

Classes:

    [JsonObject(MemberSerialization.OptIn)]
    public class Identifier
    {
        [JsonProperty]
        public string IdentifierName { get; set; }
        [JsonProperty]
        public int IdentifierNumber { get; set; }
    }
    [JsonObject(MemberSerialization.OptIn)]
    public class Locale
    {
        [JsonProperty]
        public string LocaleName { get; set; }
        [JsonProperty]            
        public int LocaleType { get; set; }
        [JsonProperty]            
        public int LocaleNumber { get; set; }
        [JsonProperty]
        public string StartTime { get; set; }
    }

    [JsonObject(MemberSerialization.OptIn)]
    public class RootObject:IRootObject
    {
       [JsonProperty]
       public string TimeGenerated { get; set; }
       [JsonProperty]        
       public double OuterValue { get; set; }
       [JsonProperty] 
       [JsonConverter(typeof(ConcreteConverter<Identifier>))]
       public IIdentifier Identifier { get; set; }
       [JsonProperty]
       [JsonConverter(typeof(ConcreteConverter<Locale>))]
       public ILocale Locale { get; set; }
       [JsonProperty]
       public double InnerValue { get; set; }
       [JsonProperty]
       public int InnerType { get; set; }
       [JsonProperty]
       public string InnerId { get; set; }
       [JsonProperty]
       public string Type { get; set; }
       [JsonProperty]
       public string Id { get; set; }
    }

      

Interface:

public interface IRootObject
{
    string TimeGenerated { get; set; }
    double OuterValue { get; set; }
    Identifier Identifier { get; set; }
    Locale Locale { get; set; }
    double InnerValue { get; set; }
    int InnerType { get; set; }
    string InnerId { get; set; }
    string Type { get; set; }
    string Id { get; set; }
}

      

The specific converter looks like this:

public class ConcreteConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    try
    {
        var s = serializer.Deserialize<T>(reader);
        return s;
    }
    catch (Exception ex)
    {
        return null;
    }
    // return serializer.Deserialize<T>(reader);
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    serializer.Serialize(writer, value);
}

      

}

I also have a list converter I made (this is a list, although this is not used, but JIC is required here):

public class ConcreteListConverter<TInterface, TImplementation> : JsonConverter where TImplementation : TInterface
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    if (existingValue == null)
        return null;

    var res = serializer.Deserialize<List<TImplementation>>(reader);
    return res.ConvertAll(x => (TInterface)x);
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    serializer.Serialize(writer, value);

}

      

}

So the problems are:

When I run:

IList<IRootObject> MyDeserialisedObject = JsonConvert.Deserialise<IList<IRootObject>>(JsonString);

      

I always get null.

When I set breakpoints on my ConcreteConverter CanConvert / ReadJson / WriteJson methods - they never hit.

What am I missing and how can I get the magic:

IList<IRootObject> MyDeserialisedObject = JsonConvert.Deserialise<IList<IRootObject>>(JsonString);

      

for the right job.

I should note that I do NOT want to just typnamehandling.objects (I think this is it) where it adds ASSEMBLYNAME.TYPE etc. to json, thereby bloating. Just assume the json above is what we need to work with and the classes presented above with their interfaces is what it needs to be deserialized to.

Hello,

chud

PS - I changed the names / properties of the classes, etc. from the real implementation to the real reality of what I do. So if they came out with an error, I apologize. But hopefully most are ok and the point / end goal is understood :)

+3


source share


3 answers


Problem

You cannot instantiate an interface that is not allowed in .NET. You cannot do this:

var items = new IList<int>(); // Not allowed

      

Your error clearly states that:

Failed to create an instance of type BLA. Type is an interface or abstract class and cannot be instantiated

Decision



Detach it to print List

, but assign a type to it IList

. Please note that the types on the right side are not interfaces in the code below, except for the casting step.

IList<IRootObject> MyDeserialisedObject = 
            JsonConvert.DeserializeObject<List<RootObject>>(File.ReadAllText(JsonString))
            .Cast<IRootObject>().ToList();

      

Some more Belabor

You may ask, "Why do I need to quit" and why can't I?

IList<IRootObject> MyDeserialisedObject = 
            JsonConvert.DeserializeObject<List<RootObject>>(File.ReadAllText(JsonString));

      

It is forbidden to save the link id .

+3


source


You are trying to force JsonConvert to create interfaces, which is not possible.

The problem is here:

IList<IRootObject> MyDeserialisedObject = JsonConvert.Deserialise<IList<IRootObject>>(JsonString);

      

  • JsonConvert will process the json data you provided.
  • Since you are asking to convert it to an object of type IList<IRootObject>

    , JsonConvert will iteratively create a list of objects IRootObject

    .
  • For each item found in the list (inside a json data string), JsonConvert will create new IRootObject()

    and populate its properties with the data it finds in the json data.

And what's the problem: new IRootObject()

not possible because you can't instantiate the interface. You can only instantiate classes.

Decision

You already have a class RootObject

. It already contains the same fields as your interface. However RootObject

, it is not currently being implemented IRootObject

.

Add the interface implementation to the class:

public class RootObject : IRootObject
{
    //make sure the implementation is correct
}

      



And then you can ask JsonConvert to give you a list RootObject

(not IRootObject

!)

List<RootObject> MyDeserialisedRootObjects = JsonConvert.Deserialise<List<RootObject>>(JsonString);

      

And if you want to turn List<RootObject>

into IList<IRootObject>

:

IList<IRootObject> MyDeserialisedIRootObjects = MyDeserialisedRootObjects.ToList<IRootObject>();

      

If you are using .NET 3.5 or below you can make the list like this:

IList<IRootObject> MyDeserialisedIRootObjects = MyDeserialisedRootObjects .Cast<IRootObject>().ToList();

      


edit I may have done this a little sneaky, but for the same reason that you cannot instantiate IRootObject

, you cannot instantiate either IList

. Both are interfaces.

The solution is the same for both: create an instance of an object that implements an interface ( List

and RootObject

), and then transfer them to their interfaces ( IList

and IRootObject

).

+1


source


I believe that you never use your own converter. According to Newtonsoft.Json documentation ( here ), you should use something like this:

IList<IRootObject> MyDeserialisedObject = JsonConvert.Deserialise<IList<IRootObject>>(JsonString, new ConcreteListConverter());

      

0


source







All Articles