Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
489 views
in Technique[技术] by (71.8m points)

json.net - C# JsonConvert using the default converter instead of the custom converter

I have a class as follows that has a custom JsonConverter:

[JsonConverter(typeof(TheShapeSerializer))]
public class TheShape : IShape {
//....
}

I cannot change the class. The way the custom serializer works is not appropriate for my needs.

Is there a way to serialize an instance of TheShape using the default serializer instead of TheShapeSerializer?

Along the same lines, is there a way to have multiple converters that can be selected at serialization time based on a given condition?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The order in which JsonConverters are selected is documented as follows:

The priority of which JsonConverter is used is member attribute, then class attribute, and finally any converters passed to the JsonSerializer.

Thus you cannot disable a JsonConverter applied via JsonConverterAttribute using JsonSerializerSettings.Converters. Instead, you have the following options.

Firstly, if your TheShape is being referred to directly by some type you control, you could grab NoConverter from this answer to Selectively use default JSON converter and apply it to the referring members using JsonConverterAttribute or JsonPropertyAttribute.ItemConverterType, e.g. as follows:

public class ShapeContainer
{
    [JsonConverter(typeof(NoConverter))]
    public TheShape Shape { get; set; }

    [JsonProperty(ItemConverterType = typeof(NoConverter))]
    public List<TheShape> Shapes { get; set; }
}

Now NoConverter will supersede TheShapeSerializer for the properties where it is applied, and cause Json.NET to fall back on default serialization.

Secondly, if you cannot add member attributes to types where TheShape is used, you could create a custom contract resolver that overrides DefaultContractResolver.ResolveContractConverter and returns null for TheShape. First define the following contract resolver:

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);
    }
}

Then, define a static member somewhere as follows, for performance reasons described here:

static IContractResolver shapeResolver = new ConverterDisablingContractResolver(new[] { typeof(TheShape) });

And serialize as follows:

var settings = new JsonSerializerSettings
{
    ContractResolver = shapeResolver,
};
var json = JsonConvert.SerializeObject(root, settings);

Demo fiddle showing both options here.

Along the same lines, is there a way to have multiple converters that can be selected at serialization time based on a given condition?

Obviously you could add different converters to JsonSerializerSettings.Converters depending on some runtime condition. But if you want to supersede statically applied converters with runtime converters, you would need to set up your types appropriately, e.g. by using OverridableJsonConverterDecorator from this answer to Why Json.net does not use customized IsoDateTimeConverter?.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...