这是我在这种情况下会做的事情。
- 子对象在父类中只有一个属性,并使其类型为
ChildObject
- 创建一个自定义
JsonConverter,它可以检查 JSON 并且:
- 如果数据存在,则反序列化子对象的完整实例,或者
- 创建子对象的新实例并设置其 ID,将所有其他属性留空。 (或者您可以按照 Jeff Mercado 的建议进行操作,让转换器根据 ID 从数据库中加载对象,如果这适用于您的情况。)
- (可选)在子对象上放置一个属性,指示它是否已完全填充。转换器可以在反序列化期间设置此属性。
反序列化后,如果 JSON 中有 ChildObject 属性(带有 ID 或完整对象值),则保证您有一个 ChildObject 实例,您可以从中获取它的 ID;否则,如果 JSON 中没有 ChildObject 属性,则父类中的 ChildObject 属性将为空。
下面是一个完整的工作示例来演示。在此示例中,我修改了父类以包含 ChildObject 的三个单独实例,以显示 JSON 中的不同可能性(仅字符串 ID、完整对象且都不存在)。他们都使用相同的转换器。我还在ChildObject 类中添加了Name 属性和IsFullyPopulated 属性。
这里是 DTO 类:
public abstract class BaseEntity
{
public string Id { get; set; }
}
public class ChildObject : BaseEntity
{
public string Name { get; set; }
public bool IsFullyPopulated { get; set; }
}
public class MyObject
{
[JsonProperty("ChildObject1")]
[JsonConverter(typeof(MyCustomObjectConverter))]
public ChildObject ChildObject1 { get; set; }
[JsonProperty("ChildObject2")]
[JsonConverter(typeof(MyCustomObjectConverter))]
public ChildObject ChildObject2 { get; set; }
[JsonProperty("ChildObject3")]
[JsonConverter(typeof(MyCustomObjectConverter))]
public ChildObject ChildObject3 { get; set; }
}
这是转换器:
class MyCustomObjectConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return (objectType == typeof(ChildObject));
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
ChildObject child = null;
if (token.Type == JTokenType.String)
{
child = new ChildObject();
child.Id = token.ToString();
child.IsFullyPopulated = false;
}
else if (token.Type == JTokenType.Object)
{
child = token.ToObject<ChildObject>();
child.IsFullyPopulated = true;
}
else if (token.Type != JTokenType.Null)
{
throw new JsonSerializationException("Unexpected token: " + token.Type);
}
return child;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer, value);
}
}
这是演示转换器操作的测试程序:
class Program
{
static void Main(string[] args)
{
string json = @"
{
""ChildObject1"":
{
""Id"": ""key1"",
""Name"": ""Foo Bar Baz""
},
""ChildObject2"": ""key2""
}";
MyObject obj = JsonConvert.DeserializeObject<MyObject>(json);
DumpChildObject("ChildObject1", obj.ChildObject1);
DumpChildObject("ChildObject2", obj.ChildObject2);
DumpChildObject("ChildObject3", obj.ChildObject3);
}
static void DumpChildObject(string prop, ChildObject obj)
{
Console.WriteLine(prop);
if (obj != null)
{
Console.WriteLine(" Id: " + obj.Id);
Console.WriteLine(" Name: " + obj.Name);
Console.WriteLine(" IsFullyPopulated: " + obj.IsFullyPopulated);
}
else
{
Console.WriteLine(" (null)");
}
Console.WriteLine();
}
}
这是上面的输出:
ChildObject1
Id: key1
Name: Foo Bar Baz
IsFullyPopulated: True
ChildObject2
Id: key2
Name:
IsFullyPopulated: False
ChildObject3
(null)