0

I'm trying to figure out how to deserialize object when every list element can have different attributes.

For example sake, lets say I have to options "a" and "b":

{
  "Email": "james@example.com",
  "CreatedDate": "2013-01-20T00:00:00Z",
  "Roles": [{
    "name": "test",
    "type": "a",
    "town": "xyz"
  },
  {
    "name": "test1",
    "type": "b" 
  }]
}

When there is a type == b then "town" can be null or shouldn't be visible, but when type == a, town should be visibile.

I tired with removing nullable fields with serialization but when I try to deserialize my class structure simply adds that "town" to every element with null value which is expected since class structure looks like that. How should class structure look like?

iMajna
  • 489
  • 4
  • 28
  • What does your class structure look like now? What would you want it to look like ideally? – Brian Rogers Nov 27 '18 at 21:24
  • Almost the same @Connell.O'Donnell set in comment below. Few minutes before I made a comment what I actually want. The first example (@Connell.O'Donnell answer) with property -> for first element you are getting as expected, for second element I'm getting name = test1, type=b, town=null. I'm trying to get rid of these "town=null" in list of elements so I have just => name = test1, type=b – iMajna Nov 27 '18 at 21:26
  • Are you saying that for type A you want to use a class that has a `Town` property, but for type B you want to use a class that does not have a `Town` property? If so, you can use a custom JsonConverter to deserialize-- see [Deserializing polymorphic json classes without type information using json.net](https://stackoverflow.com/q/19307752/10263) – Brian Rogers Nov 27 '18 at 21:36

1 Answers1

0

You could pass the NullValueHandling flag to the JsonProperty attribute if you're using Newtonsoft. Here's an example in their documentation:

https://www.newtonsoft.com/json/help/html/JsonPropertyPropertyLevelSetting.htm

Edit Try creating the following object structure:

public class Person
{
    public string Email { get; set; }
    public DateTime CreatedDate { get; set; }
    public List<Role> Roles { get; set; }
}

public class Role
{
    public string name { get; set; }
    public string type { get; set; }

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public string town { get; set; }
}

Then copy that json into a file and deserialize like this

string json = File.ReadAllText("a.json");
Person person = JsonConvert.DeserializeObject<Person>(json);

Edit

Well, if you really don't want to see that property at all, you're going to end up with some ugly code. Here's a quick and dirty example that works.

public class PersonA
{
    public string Email { get; set; }
    public DateTime CreatedDate { get; set; }
    public List<RoleB> Roles { get; set; }       
}

public class RoleB : RoleA
{
    public string town { get; set; }
}

public class PersonB
{
    public string Email { get; set; }
    public DateTime CreatedDate { get; set; }
    public List<RoleA> RolesA { get; set; } = new List<RoleA>();
    public List<RoleB> RolesB { get; set; } = new List<RoleB>();
}

public class RoleA
{
    public string name { get; set; }
    public string type { get; set; }
}

Then doing something like this:

string json = File.ReadAllText("a.json");
PersonA personA = JsonConvert.DeserializeObject<PersonA>(json);
PersonB personB = new PersonB() { Email = personA.Email, CreatedDate = personA.CreatedDate };

foreach(var role in personA.Roles)
{
    var roleB = role as RoleB;
    if (roleB.town != null)
    {
        personB.RolesB.Add(roleB);
    }
    else
    {
        personB.RolesA.Add(new RoleA() { name = roleB.name, type = roleB.type });
    }
}
Connell.O'Donnell
  • 3,603
  • 11
  • 27
  • 61
  • That property works fine until you try do deserialize object. NullValueHandling is just for serialization. As I said, after deserialization I'm still getting attributes with null values in object – iMajna Nov 27 '18 at 20:19
  • @Superbrain_bug you can't NOT have a property. The only way around would be to have two different implementations of `Role` but then you're getting into a whole mess of issues with having to read the json first, look for a value, based on it's value then deciding which class to deserialize into. – gilliduck Nov 27 '18 at 20:46
  • I know I can't go with property that's why I'm asking best way to implement this – iMajna Nov 27 '18 at 20:48
  • @Connell.O'Donnell the first example with property -> for first element you are getting as expected, for second element I'm getting name = test1, type=b, town=null. I'm trying to get rid of these "town=null" in list of elements so I have just => name = test1, type=b I'll try second example asap and will get let you know, but I see where it is going :( – iMajna Nov 27 '18 at 21:16