您可以利用应用于属性的转换器优先于其他转换器这一事实来为A _x 使用自定义转换器实例。
正如其Serialization Guide 中所解释的:
JsonConverters 可以在许多地方定义和指定:在成员的属性中,在类的属性中,以及添加到 JsonSerializer 的转换器集合中。 使用JsonConverter的优先级是成员上的属性定义的JsonConverter,然后是类上的属性定义的JsonConverter,最后是传递给JsonSerializer的任何转换器。
这使得在使用converter parameters 应用于A _x 时,可以将声明的类型信息(或任何其他编译时信息)传递给MyConverter。在 cmets 中,您编写了 我需要向自定义转换器显示编译时类型,所以如果 编译时类型 您的意思是 声明的类型 A _x 你可以这样做。
修改MyConverter以添加带有declaredType参数的构造函数:
class MyConverter : JsonConverter
{
public MyConverter() : this(typeof(A)) { }
public MyConverter(Type declaredType) => this.DeclaredType = declaredType;
public Type DeclaredType { get; init; }
public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer)
{
// This is just a mockup, your question doesn't specify your requirements.
var a = (A)value;
writer.WriteStartObject();
if (DeclaredType == typeof(A) && a is B b)
{
//By in the case of CA, MyConverter should tag what it serialises in some defined way
writer.WritePropertyName("isB");
writer.WriteValue(true);
}
// Add whatever logic you need to serialize A
// Add whatever additional logic you need to serialize B
// And end the object
writer.WriteEndObject();
}
public override bool CanConvert(Type objectType) => typeof(A).IsAssignableFrom(objectType);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => throw new NotImplementedException();
}
然后如下修改你的类:
class CA {
[JsonConverter(typeof(MyConverter), typeof(A))]
public readonly A _x;
public CA(A _x) { this._x = _x; } // The constructor argument names must have the same case-invariant name as the corresponding member for the converter to be applied
}
class CB {
[JsonConverter(typeof(MyConverter), typeof(B))]
public readonly B _x;
public CB(B _x) { this._x = _x; }
}
[JsonConverter(typeof(MyConverter))]
class A {
}
[JsonConverter(typeof(MyConverter), typeof(B))]
class B : A {
}
或者,您可以在声明的类型中创建MyConverter generic:
class MyConverter<TDeclared> : JsonConverter<TDeclared> where TDeclared : A
{
public override void WriteJson( JsonWriter writer, TDeclared value, JsonSerializer serializer)
{
// This is just a mockup, your question doesn't specify your requirements.
writer.WriteStartObject();
if (typeof(TDeclared) != value.GetType())
{
//By in the case of CA, MyConverter should tag what it serialises in some defined way
writer.WritePropertyName("isB");
writer.WriteValue(value.GetType() == typeof(B));
}
// Add whatever logic you need to serialize A
// Add whatever additional logic you need to serialize B
// And end the object
writer.WriteEndObject();
}
public override TDeclared ReadJson(JsonReader reader, Type objectType, TDeclared existingValue, bool hasExistingValue, JsonSerializer serializer) => throw new NotImplementedException();
}
并应用如下:
class CA {
[JsonConverter(typeof(MyConverter<A>))]
public readonly A _x;
public CA(A _x) { this._x = _x; } // The constructor argument names must have the same case-invariant name as the corresponding member for the converter to be applied
}
class CB {
[JsonConverter(typeof(MyConverter<B>))]
public readonly B _x;
public CB(B _x) { this._x = _x; }
}
[JsonConverter(typeof(MyConverter<A>))]
class A {
}
[JsonConverter(typeof(MyConverter<B>))]
class B : A {
}
无论哪种方式,CA ca 都会被序列化如下:
{"_x":{"isB":true}}
虽然CB cb 仍会像这样被序列化:
{"_x":{}}
注意事项:
-
由于 Json.NET 是一个基于契约的序列化器,它在序列化对象时通常不会提供有关当前序列化堆栈的信息。父对象决定序列化什么,子对象决定如何序列化自己。因此,例如MyConverter 不会被告知容器对象的类型是 CA 还是 CB 或者正在写入该容器的特定属性。
自定义成员转换器是该一般原则的一个显着例外。
-
在这两种情况下,我的代码都假定您不希望在独立序列化时标记B。如果您确实希望将其标记为独立,请编辑您的问题以澄清。
-
当使用参数化构造函数反序列化不可变类型时,Json.NET 使用大小写不变匹配将参数名称与属性匹配,以便使用查找和使用可能应用于属性的 [JsonProperty] 或 [JsonConverter] 属性。因此,我将您的构造函数参数名称修改为 _x 以确保在反序列化期间应用 MyConverter。
演示小提琴#1 here 用于参数化转换器,#2 here 用于通用版本。