One possibility could be to create a JsonConverter.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false)]
public sealed class ImportChildAttribute : Attribute
{
}
class ImportChildJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
var attr = CustomAttributeExtensions.GetCustomAttribute(objectType.GetTypeInfo(), typeof(ImportChildAttribute), true);
if (attr != null)
{
var props = objectType.GetProperties();
if (props.Length != 1)
throw new NotSupportedException($"Only supports {nameof(ImportChildAttribute)} on classes with one property.");
return true;
}
return false;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// Deserialize the object into the first property.
var props = objectType.GetProperties();
var obj = Activator.CreateInstance(objectType);
var val = serializer.Deserialize(reader, props[0].PropertyType);
props[0].SetValue(obj, val);
return obj;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// Find the only property and serialize it.
var props = value.GetType().GetProperties();
serializer.Serialize(writer, props[0].GetValue(value));
}
}
Then you can put the ImportChild attribute on all the classes you want to have this behaviour.
[ImportChild]
public class A
{
[JsonProperty(PropertyName = "prop_b")]
public B PropB { get; set; }
}
public class B
{
[JsonProperty(PropertyName = "val1")]
public int Val1 { get; set; }
[JsonProperty(PropertyName = "val2")]
public int Val2 { get; set; }
}
Finally, try it out:
var settings = new JsonSerializerSettings
{
Converters = new[] { new ImportChildJsonConverter() },
Formatting = Formatting.Indented
};
var obj = new A { PropB = new B { Val1 = 1, Val2 = 2 } };
string json = JsonConvert.SerializeObject(obj, settings);
Console.WriteLine(json);
/* Outputs:
{
"val1": 1,
"val2": 2
}
*/
var originalObj = JsonConvert.DeserializeObject<A>(json, settings);
// originalObj and obj are now identical.
Ahas more than one field