我有一个类如下,它有一个自定义的JsonConverter
:
[JsonConverter(typeof(TheShapeSerializer))]
public class TheShape : IShape {
//....
}
我无法更改类。自定义序列化程序的工作方式不适合我的需求。
是否有一种方法可以使用默认序列化程序而不是TheShapeSerializer来序列化TheShape的实例?
同样,在这方面,是否有一种方法可以根据给定条件在序列化时选择多个转换器?
JsonConverters的选择顺序如下documented:
使用的JsonConverter的优先级为成员属性,然后是类属性,最后是传递给JsonSerializer的任何转换器。
因此,您无法使用JsonSerializerSettings.Converters
禁用通过JsonConverterAttribute
应用的JsonConverter
。 相反,您有以下选项。
首先,如果您直接引用了某个类型的TheShape
,则可以从this answer中获取NoConverter
以Selectively use default JSON converter并使用JsonConverterAttribute
或JsonPropertyAttribute.ItemConverterType
将其应用于引用成员,例如:
public class ShapeContainer
{
[JsonConverter(typeof(NoConverter))]
public TheShape Shape { get; set; }
[JsonProperty(ItemConverterType = typeof(NoConverter))]
public List<TheShape> Shapes { get; set; }
}
NoConverter
将代替应用了它的属性中的TheShapeSerializer
,并导致Json.NET回退到默认序列化。TheShape
的类型添加成员属性,可以创建一个自定义合同解析器,覆盖DefaultContractResolver.ResolveContractConverter
并返回null
以供TheShape
使用。首先定义以下合同解析器:public class ConverterDisablingContractResolver : DefaultContractResolver
{
readonly HashSet<Type> types;
public ConverterDisablingContractResolver(IEnumerable<Type> types)
{
if (types == null)
throw new ArgumentNullException();
this.types = new HashSet<Type>(types);
}
bool ContainsType(Type type)
{
return types.Contains(type);
}
protected override JsonConverter ResolveContractConverter(Type objectType)
{
// This could be enhanced to deal with inheritance. I.e. if TBase is in types and has a converter then
// its converter should not be used for TDerived -- but if TDerived has its own converter then it should still be
// used, so simply returning null for TDerived would be wrong.
if (types.Contains(objectType))
return null;
return base.ResolveContractConverter(objectType);
}
}
然后,为了性能考虑,按照这里所述,在某个地方定义一个静态成员:
static IContractResolver shapeResolver = new ConverterDisablingContractResolver(new[] { typeof(TheShape) });
然后按照以下方式进行序列化:
var settings = new JsonSerializerSettings
{
ContractResolver = shapeResolver,
};
var json = JsonConvert.SerializeObject(root, settings);
演示fiddle展示了两个选项在这里。
同样的,是否有一种方法可以有多个转换器,在序列化时根据给定条件进行选择?
显然,您可以根据某些运行时条件向JsonSerializerSettings.Converters
添加不同的转换器。但是,如果您想使用运行时转换器取代静态应用的转换器,则需要适当设置类型,例如通过使用此答案中的OverridableJsonConverterDecorator
来回答为什么Json.net不使用自定义IsoDateTimeConverter?。
var json = JsonConvert.SerializeObject(obj, new MyCustomConverter())
时,您可以尝试使用另一个转换器。这样您就可以更好地控制整个过程。 - NkosiJsonConverter
优先于通过设置应用的JsonConverter
。根据文档:使用的JsonConverter
的优先级是成员属性、类属性,最后是传递给 JsonSerializer 的任何转换器。 您需要使用 自定义契约解析器。 - dbc