I'm trying to read a json fragment in a C# application.
In the fragment, there's an array that can contains either a simple string or a complex object. This is because the contained object has only one mandatory string, other fields are optional. Thus, to simplify the json, the array can contain a string (= default parameters) or the complex object.
Here is a sample json :
{
"Config1": [
"Simple string 1",
"Simple string 2",
{
"Data": "Complex object",
"OptionalField": "some option",
"AnotherOption": 42
}
],
"Config3": [
"Simple string 3",
"Simple string 4",
{
"Data": "Complex object 2",
"OptionalField": "some option",
"AnotherOption": 12
}
]
}
The corresponding C# model :
public class Config : Dictionary<string, ConfigItem[]>
{
}
public class ConfigItem
{
public ConfigItem()
{
}
public ConfigItem(string data)
{
this.Data = data;
}
public string Data { get; set; }
public string OptionalField { get; set; }
public int AnotherOption { get; set; }
}
In my sample, only the Data
field is mandatory. When a string is supplied, the constructor with a single string parameter must be called. When a complex json object is provided, the standard deserialization must run.
For example, these two json fragments are equivalent (within the array):
"Config4": [
"This is a string",
{
"Data": "This is a string",
"OptionalField": null,
"AnotherOption": 0
}
]
How to reach my goal ?
Right now, I tried to implement a custom converter :
[JsonConverter(typeof(StringToComplexConverter))]
public class ConfigItem
{
// Properties omiited
}
public class StringToComplexConverter : JsonConverter<ConfigItem>
{
public override bool CanWrite => false;
public override ConfigItem ReadJson(JsonReader reader, Type objectType, ConfigItem existingValue, bool hasExistingValue, JsonSerializer serializer)
{
if(reader.TokenType == JsonToken.String)
{
var ctor = objectType.GetConstructor(new[] { typeof(string) });
return (ConfigItem)ctor.Invoke(new[] { (string)reader.Value });
}
else
{
// What to put in the else ?
}
}
public override void WriteJson(JsonWriter writer, ConfigItem value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
This is actually working for strings. However, I didn't find what to put in the else
statement. Is there a way to forward to standard deserialization from the ReadJson method ?
If I put return serializer.Deserialize<ConfigItem>(reader);
in my else statement, it ends in a infinite loop.
Also tried return serializer.Deserialize<JObject>(reader).ToObject<ConfigItem>();
, with no success.