【发布时间】:2018-05-13 07:56:48
【问题描述】:
我有一个泛型类型,它包装了一个原始类型以赋予它值相等语义
public class ValueObject<T>
{
public T Value { get; }
public ValueObject(T value) => Value = value;
// various other equality members etc...
}
用法如下:
public class CustomerId : ValueObject<Guid>
{
public CustomerId(Guid value) : base(value) { }
}
public class EmailAddress : ValueObject<string>
{
public EmailAddress(string value) : base(value) { }
}
问题是在序列化如下类型时:
public class Customer
{
public CustomerId Id { get; }
public EmailAddress Email { get; }
public Customer(CustomerId id, EmailAddress email)
{
Id = id;
Email = email;
}
}
从ValueObject<T> 继承的每个对象都包含在Value 属性中(如预期的那样)。例如
var customerId = new CustomerId(Guid.NewGuid());
var emailAddress = new EmailAddress("some@email.com");
var customer = new Customer(customerId, emailAddress);
var customerAsJson = JsonConvert.SerializeObject(customer, Formatting.Indented, new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
})
结果
{
"id": {
"value": "f5ce21a5-a0d1-4888-8d22-6f484794ac7c"
},
"email": {
"value": "some@email.com"
}
}
有没有办法编写自定义 JsonConverter 以便为子类化 ValueObject<T> 的类型排除 Value 属性,以便上面的示例输出
{
"id": "f5ce21a5-a0d1-4888-8d22-6f484794ac7c",
"email": "some@email.com"
}
我希望有一个可以处理所有ValueObject<T> 的JsonConverter,而不是必须为每个ValueObject<T> 子类定义一个单独的JsonConverter
我的第一次尝试是
public class ValueObjectOfTConverter : JsonConverter
{
private static readonly Type ValueObjectGenericType = typeof(ValueObject<>);
private static readonly string ValuePropertyName = nameof(ValueObject<object>.Value);
public override bool CanConvert(Type objectType) =>
IsSubclassOfGenericType(objectType, ValueObjectGenericType);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// converts "f5ce21a5-a0d1-4888-8d22-6f484794ac7c" => "value": "f5ce21a5-a0d1-4888-8d22-6f484794ac7c"
var existingJsonWrappedInValueProperty = new JObject(new JProperty(ValuePropertyName, JToken.Load(reader)));
return existingJsonWrappedInValueProperty.ToObject(objectType, serializer);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// to implement
}
private static bool IsSubclassOfGenericType(Type typeToCheck, Type openGenericType)
{
while (typeToCheck != null && typeToCheck != typeof(object))
{
var cur = typeToCheck.IsGenericType ? typeToCheck.GetGenericTypeDefinition() : typeToCheck;
if (openGenericType == cur) return true;
typeToCheck = typeToCheck.BaseType;
}
return false;
}
}
【问题讨论】:
-
当然,您可以添加custom
JsonConverter,就像Json.Net: Serialize/Deserialize property as a value, not as an object 中显示的那样。但是使用转换器有时会干扰多态性和TypeNameHandling。您是否曾经使用ValueObject<T>来为原语保留类型信息?为什么只适用于子类化ValueObject<T>? -
或者,你写
JsonConverter.CanConvertmethod有困难吗? -
我已经更新了这个问题。我宁愿不必为每个子类编写自定义转换器。