Casting Interfaces for Deserialization in JSON.Net

Casting interfaces for deserialization in JSON.NET

@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; }
}

Json deserialize a complex object with an Interface as a property

It turns out that I can change the property in the TaskDetail from IBehavior to dynamic and it works. Then when I need to use the concrete type I have a factory that can return a concrete type (i.e. torqueTool). At that point I can do

JsonConvert.DeserializeObject<TorqueTool>(taskDetail.Behavior.ToString());

Deserialization by JSON.NET of a list of interfaces inside another class

you must pass a "model" instead of "AggregatorItem" here:

// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse); 
public class Item
{
[JsonProperty("$type")]
public string Type { get; set; }
public bool IsPublished { get; set; }
public int UId { get; set; }
public int OwnerUId { get; set; }
public string Name { get; set; }
public int UIdStreet { get; set; }
public int UIdArea { get; set; }
}

public class Root
{
[JsonProperty("$type")]
public string Type { get; set; }
public int UId { get; set; }
public string Name { get; set; }
public bool IsPublished { get; set; }
public List<Item> Items { get; set; }
}


var lstAggregatorItem = JsonConvert.DeserializeObject<List<Root>>(tokenAggregators.ToString());

Deserialize collection of interface-instances?

Bellow full working example with what you want to do:

public interface ITestInterface
{
string Guid { get; set; }
}

public class TestClassThatImplementsTestInterface1 : ITestInterface
{
public string Guid { get; set; }
public string Something1 { get; set; }
}

public class TestClassThatImplementsTestInterface2 : ITestInterface
{
public string Guid { get; set; }
public string Something2 { get; set; }
}

public class ClassToSerializeViaJson
{
public ClassToSerializeViaJson()
{
this.CollectionToSerialize = new List<ITestInterface>();
}
public List<ITestInterface> CollectionToSerialize { get; set; }
}

public class TypeNameSerializationBinder : SerializationBinder
{
public string TypeFormat { get; private set; }

public TypeNameSerializationBinder(string typeFormat)
{
TypeFormat = typeFormat;
}

public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
assemblyName = null;
typeName = serializedType.Name;
}

public override Type BindToType(string assemblyName, string typeName)
{
var resolvedTypeName = string.Format(TypeFormat, typeName);
return Type.GetType(resolvedTypeName, true);
}
}

class Program
{
static void Main()
{
var binder = new TypeNameSerializationBinder("ConsoleApplication.{0}, ConsoleApplication");
var toserialize = new ClassToSerializeViaJson();

toserialize.CollectionToSerialize.Add(
new TestClassThatImplementsTestInterface1()
{
Guid = Guid.NewGuid().ToString(), Something1 = "Some1"
});
toserialize.CollectionToSerialize.Add(
new TestClassThatImplementsTestInterface2()
{
Guid = Guid.NewGuid().ToString(), Something2 = "Some2"
});

string json = JsonConvert.SerializeObject(toserialize, Formatting.Indented,
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto,
Binder = binder
});
var obj = JsonConvert.DeserializeObject<ClassToSerializeViaJson>(json,
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto,
Binder = binder
});

Console.ReadLine();
}
}

Casting interfaces for deserialization in JSON.NET

@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; }
}

Deserializing interface objects in JSON.NET

You need to deserialize to a concrete class because the behaviour of that class must be defined. You need a Thingy : IThingy at which point I would do:

IThingy result = response.Content.ReadAsAsync<Thingy>().Result;

Why must you do this? Interfaces define no behaviour, only signatures of methods and properties. Say you were able to deserialize directly to IThingy and it had a method DoMath(int x, int y) - what math would be done? There would be no defined behaviour. That's why you must choose a concrete class.



Related Topics



Leave a reply



Submit