tmesser tmesser - 1 month ago 8
C# Question

Casting interfaces for deserialization in JSON.NET

I am trying to set up a reader that will take in JSON objects from various websites (think information scraping) and translate them into C# objects. I am currently using JSON.NET for the deserialization process. The problem I am running into is that it does not know how to handle interface-level properties in a class. So something of the nature:

public IThingy Thing


Will produce the error:


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


It is relatively important to have it be an IThingy as opposed to a Thingy since the code I am working on is considered sensitive and unit testing is highly important. Mocking of objects for atomic test scripts is not possible with fully-fledged objects like Thingy. They must be an interface.

I've been poring over JSON.NET's documentation for a while now, and the questions I could find on this site related to this are all from over a year ago. Any help?

Also, if it matters, my app is written in .NET 4.0.

Answer

@SamualDavis provided a great solution in a related question, which I'll summarize here.

If you have to deserialize a JSON stream into a concrete class that has interface properties, you can include the concrete classes as parameters to a constructor for the class! The NewtonSoft deserializer is smart enough to figure out that it needs to use those concrete classes to deserialize the properties.

Here is an example:

public class Visit : IVisit
{
    /// <summary>
    /// This constructor is required for the JSON deserializer to be able
    /// to identify concrete classes to use when deserializing the interface properties.
    /// </summary>
    public Visit(MyLocation location, Guest guest)
    {
        Location = location;
        Guest = guest;
    }
    public long VisitId { get; set; }
    public ILocation Location { get;  set; }
    public DateTime VisitDate { get; set; }
    public IGuest Guest { get; set; }
}