3

I was wondering if I have an object that contains a field which has its deserialization process dependant on another field, how can I deserialize the parent object?

Container

class Container
{ 
    public int Id { get; set; }
    public object Data { get; set; } //deserialization depends on first field
}

Hierarchy

class FieldType1
{
    public string Value { get; set; }
}

class FieldType2
{
    public int Numbers { get; set; }
}

Given the example above if I have a Dictionary<int,Type> how can I deserialize an object that comes as a string like the one below?:

var container = new Container { Data = new FieldType1 { Value = "sata" }};
var str = JsonConvert.SerializeObject(container);
var clone = JsonConvert.DeserializeObject<Container>(str);//has dependant field on another field

As you can see in my example above I always have the same container type.but one property differs.

Update

After some answers here could it be possible to keep only one type of parent object and instead have a base type for the second field ?

  [JsonSubTypes.KnownSubType(typeof(Child1),1)]
  [JsonSubTypes.KnownSubType(typeof(Child2),2)]
  public abstract Child
  {
  }


 public class Parent{
 public int Id;
 public Child child;

 }

Can i decorate somehow the parent to know how to deserialize its second field (similar to JsonSubTypes)?


Summing it up i do not want to have P,P1,P2..Pn types for parent. I want to have one type P for parent with F1,F2...Fn types for its second field.So that when i deserialize i would just say JsonConvert.DeserializeObject<P> while the converter takes care of which concrete type is the second field:

 Parent c1=new P{ id=1,child=new Child1()};
 Parent c2=new P{ id=2,child=newChild2()};
 List<Parent> items=new List<Parent>{c1,c2};
 var str=JsonConvert.SerializeObject(items);

 var clone=JsonConvert.DeserializeObject<List<Parent>>(str);
Bercovici Adrian
  • 8,794
  • 17
  • 73
  • 152
  • Why not use a string for all values? – Alan Turing Feb 28 '19 at 21:55
  • 1
    How many different object types are there, that can be derived from the first field? – Ralph Willgoss Feb 28 '19 at 22:25
  • 1
    There are already several questions about this including [How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects?](https://stackoverflow.com/q/8030538/3744182), [Deserializing polymorphic json classes without type information using json.net](https://stackoverflow.com/q/19307752/3744182), [Json.net serialize/deserialize derived types?](https://stackoverflow.com/q/8513042/3744182) and [how to deserialize JSON into IEnumerable with Newtonsoft JSON.NET](https://stackoverflow.com/q/6348215/3744182). Do any of those meet you needs? – dbc Feb 28 '19 at 23:36
  • I have read the implementations abd looked over the internet.But i would like in my case to have only one type of parent object, and keep the second field as a base class. – Bercovici Adrian Mar 01 '19 at 04:58
  • @Ralph there would be some tens of objects (50-90) types at least.That is why i want to keep only one type of parent and have instead a base abstract class for the second field. – Bercovici Adrian Mar 01 '19 at 05:04
  • Do you control the objects being serialized? Whoever is serialising the objects for you, will need to include a $type:"dot.net.type" definition in the Json. This can then allow you to use some inbuilt functionality in Json.Net, for it to work out what object to deserialise to – Ralph Willgoss Mar 01 '19 at 09:33
  • This post gives a good overview of "TypeNameHandling", https://skrift.io/articles/archive/bulletproof-interface-deserialization-in-jsonnet. Its using interfaces but you can adapt as need be as the concept is the same. – Ralph Willgoss Mar 01 '19 at 09:50
  • But i need to do a mapping first since i will not receive the `type` as a string but as an int.Therefore i would first need to deserialize the `parent` object then take his `id` field , look it up in a `Dictionary` and the deserialize the `child` field accordingly.I would not want to `deserialize` 2 times. – Bercovici Adrian Mar 01 '19 at 10:13

1 Answers1

2

At a first glance, I'd simply use a simple function that you could put into a SomeNameParser/Converter class.

Pesudo C# code, something like the following:

var jObject = JObject.Parse(obj.Data);
switch (jObject["firstField"])
{
   case "fieldType1":
     return JsonConvert.DeserializeObject<string>(str);

   case "fieldType2":
     return JsonConvert.DeserializeObject<int>(str);

   default:
     Throw new Exception( make this meaningful)
}

Improvements
You could make the parsing of the firstField do a lookup to return a System.Type, then pass the type to JsonConvert.Deserialize(obj.Data, type) which would save the repetitive JsonConvert.

Hopefully you can see the general pattern.

Ralph Willgoss
  • 11,750
  • 4
  • 64
  • 67
  • Indeed in this case i am solving the second field.But when i am deserializing the parent , i want only one type of parent.How could i specify at parent deserialization that its field is of type `X` without deriving the parent. – Bercovici Adrian Mar 01 '19 at 05:00