In my little library I'm writing as a side project, I'm using RestSharp to get Json from a web API. The deserialization into model classes works fine for simple types, but there are endpoints where the resulting type is unknown (or unclear) at request time.
Specifically its the GuildWars2 API v1 and one example would be item data. There are of course basic properties every item has and additional values are set depending on the queried item. For example a weapon has some modifiers and so on.
My idea was to create an abstract Item class for all basic properties and derive from that class for all the existing subtypes of items adding needed properties. My problem is, how to decide which subclass to deserialize into. I already read about various methods involving adding a qualified type name to the Json string but since I only get the data from an API, I cannot influence the response im getting.
I would ideally always want to deserialize into the base class Item with the deserializer deciding the actual type via the given properties contained in the Json string.. Is this a possibility? Or is there a better way to solve this problem?
Thanks in advance
EDIT: This is an example Json of a weapon:
{
"item_id": "30704",
"name": "Twilight",
"description": "",
"type": "Weapon",
"level": "80",
"rarity": "Legendary",
"vendor_value": "100000",
"icon_file_id": "456031",
"icon_file_signature": "CE3AF0B7B9BB6244726779F5B6A930541BA6C15F",
"game_types": ["Activity", "Dungeon", "Pve", "Wvw"],
"flags": ["HideSuffix", "NoSell", "SoulBindOnUse"],
"restrictions": [],
"weapon": {
"type": "Greatsword",
"damage_type": "Physical",
"min_power": "995",
"max_power": "1100",
"defense": "0",
"infusion_slots": [],
"infix_upgrade": {
"attributes": [
{
"attribute": "Power",
"modifier": "179"
},
{
"attribute": "Power",
"modifier": "179"
}
]
},
"suffix_item_id": "24599"
}
}
And this would be an armor piece:
{
"item_id":"500",
"name":"Carrion Conjurer Chest of Dwayna",
"description":"",
"type":"Armor",
"level":"68",
"rarity":"Rare",
"vendor_value":"257",
"icon_file_id":"61023",
"icon_file_signature":"76CD08463A05730071D400254141B50E570662D3",
"game_types":["Activity", "Dungeon", "Pve", "Wvw"],
"flags":["SoulBindOnUse"],
"restrictions":[],
"armor": {
"type":"Coat",
"weight_class":"Light",
"defense":"221",
"infusion_slots":[],
"infix_upgrade": {
"attributes": [
{
"attribute":"ConditionDamage","modifier":"70"
},
{
"attribute":"Power","modifier":"50"
}
]
},
"suffix_item_id":"24767"
}
}
I'd like to deserialize based on the content of the property "Type", but I cannot figure out, how that would work =/
You can parse your JSON data with JObject, which then can be used as an associative array.
string json = @"{
"item_id": "30704",
"name": "Twilight",
"description": "",
"type": "Weapon",
...
}";
JObject o = JObject.Parse(json);
Item item = null;
switch (o["type"])
{
case "Weapon":
item = JsonConvert.DeserializeObject<Weapon>(json);
break;
case "Armor":
item = JsonConvert.DeserializeObject<Armor>(json);
break;
default:
// throw error?
}
and then you'd have a base class as such:
public class Item
{
public string item_id { get; set; }
public string name { get; set; }
public string description { get; set; }
public string type { get; set; }
...
// List all common properties here
public Item() { }
// It's important to have the public default constructor implemented
// if you intend on overloading it for your own purpose later
}
And your Weapon class could be as such:
public class Weapon : Item // Weapon extends Item
{
public WeaponDetails weapon { get; set; }
public Weapon() { }
}
And Weapon Details:
public class WeaponDetails
{
public string type { get; set; }
public string damage_type { get; set; }
public int min_power { get; set; }
public int max_power { get; set; }
...
public WeaponDetails() { }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With