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
How to Find All Combinations of Items in an Array
When to Use Ref and When It Is Not Necessary in C#
Prevent Caching in ASP.NET MVC for Specific Actions Using an Attribute
How to Write a Backslash (\) in a String
Set Timeout for Webclient.Downloadfile()
How to Split a String with a String Delimiter
Update Row If It Exists Else Insert Logic with Entity Framework
How to Assign a Base Class Object to a Derived Class Reference with an Explicit Typecast
Is There a Way of Setting Culture for a Whole Application? All Current Threads and New Threads
Make Https Call Using Httpclient
C# Download All Files and Subdirectories Through Ftp
How to Concatenate Two Arrays in C#