I have a json structure, that a few levels down turns a generic object
into one that would need to be converted into a Custom Object
type for further processing.
Cut down example to show what I mean:
{
"main": [
{
...
"list": [
{
...
"sublist": [
{
...
"items": [
{
<identical structure> <-- Section sets parameters, static strings
"Generic Object": {...} <-- Becomes ObjectType1 object, based on above
},
{
<identical structure> <-- Section sets parameters, static strings
"Generic Object": {...} <-- Becomes ObjectType2 object, based on above
}]
}]
}]
}]
}
I have the "Generic Object" set simply to type Object
in initial de-serialization. However, when I try to convert it to a more specialized type by
var object = (TypecastObjectType1)<locationOfObject>.VariableObject;
This results in an error at that specific line:
'Unable to cast object of type 'Newtonsoft.Json.Linq.JObject' to type 'TypecastObjectType1'.'
Looking at source Json and the structure, it’s matching my custom get-set class layout, so I am obviously missing something.
The reason it’s a generic object itself, is because it is only typecast when that specific part is used/interacted with, which would then set the object type at that point for a more specialized selections of contents for that specific operation type.
2
Answers
The error message tells me that the
<locationOfObject>.VariableObject
is obtained using LINQ to JSON, so its type isJObject
. To deserialize aJObject
into a .NET object, you should consider using<locationOfObject>.VariableObject.ToObject<TypecastObjectType1>()
instead of a simple cast.To handle "Generic Objects", I’d suggest creating a custom serialization binder. Your JSON will look like this:
The binder itself is a class derived from
Newtonsoft.Json.Serialization.DefaultSerializationBinder
. In your case it will look like this:To inject this binder you’ll need the following
JsonSerializerSettings
:In OOP we know inheritance can go from least specific most common (object) to most specific, most complex merely by containing the proper interface definitions. The runtime has no problem morphing into one or more of the types of any implementated interface merely by casting.
The other ability to morph objects is using the Containment method. Any object may contain one or many other objects. For example a car can contain 4 tires. The tires are not a car, rather the car contains the tires. We typically don’t downcast a Tire to an object because we loose knowledge of what it is. Class names carry meaning and all classes start as objects. This is why we can call the ToString method on tire to see a console output.
Storing objects as Json has no bad effect on any object. This is due to the excellent schema of json and libraries like Newtonsoft.Json that converts from string to object types with simplicity.
One last point is that of generics. With generics there are behavioral concerns. For example lists are perfect for generics because we don’t care what type of list they are we just care about iteration, summation, averages and counts.
If you are running a car shop which does tire maintenance. You first will only accept cars. Then you will want the tire information to get specs. The maintenance is done on the tires including possible replacement. All being certified work based on tire and car maker recommendations.
Favor composition over inheritance and serialize to string for storage. Use ORM to convert strings to objects. Good luck.