简体   繁体   English

如何覆盖默认的 JsonConverter(在属性中指定)

[英]How to Override a Default JsonConverter (specified in an attribute)

I would like the following Author type to have a default JsonConverter , and be able to override it at runtime.我希望以下Author类型具有默认的JsonConverter ,并且能够在运行时覆盖它。

[JsonConverter(typeof(BaseJsonConverter))]
public class Author
{
    // The ID of an author entity in the application.
    public int ID { set; get; }

    // The ID of an Author entity in its source.
    public string SourceID { set; set; }
}

I used the following code to override the default converter (ie, BaseJsonConverter ).我使用以下代码覆盖默认转换器(即BaseJsonConverter )。

public class AlternativeConverter : BaseJsonConverter
{ // the serializer implementation is removed for clarity. }

// Deserialize using AlternativeConverter:
var author = JsonConvert.DeserializeObject<Author>(jsonString, new AlternativeConverter());

Question

Using the above call, the AlternativeConverter is first constructed;使用上面的调用,首先构造了AlternativeConverter however, then an instance of BaseJsonConverter is initialized and used for deserialization.然而,然后BaseJsonConverter一个实例被初始化并用于反序列化。 So, the AlternativeConverter is never used.因此,从不使用AlternativeConverter

Executable example: https://dotnetfiddle.net/l0bgYO可执行示例:https://dotnetfiddle.net/l0bgYO


Use case用例

The application is to convert different JSON objects, obtained from different sources, to a common C# type.应用程序是将从不同来源获得的不同 JSON 对象转换为通用 C# 类型。 Commonly data comes from a source for that we define the default converter (ie, BaseJsonConverter ), and for data coming from other sources, we define different converters per each.通常数据来自我们定义默认转换器的源(即BaseJsonConverter ),对于来自其他源的数据,我们为每个源定义不同的转换器。


Background背景

I am aware of methods such as this one , and indeed I am using similar method partially.我知道的方法,如这一个,而事实上我使用类似的方法部分。 With ref to that article, I need to have different _propertyMappings depending on the source of input, because in my application attribute to property mapping is not one-to-one.参考那篇文章,我需要根据输入源使用不同的_propertyMappings ,因为在我的应用程序中,属性到属性的映射不是一对一的。 For instance, I have the following JSON objects:例如,我有以下 JSON 对象:

{
   "id":123
}

// and

{
   "id":"456"
}

where the first JSON object should be deserialized to:第一个 JSON 对象应该反序列化为:

author.ID = 123
author.SourceID = null

and the second JSON object should be deserialized as:并且第二个 JSON 对象应该反序列化为:

author.ID = 0
author.SourceID = "456"

You can use a custom ContractResolver to override a [JsonConverter] attribute programmatically.您可以使用自定义ContractResolver以编程方式覆盖[JsonConverter]属性。 To solve your problem you could make a custom resolver like this:要解决您的问题,您可以制作这样的自定义解析器:

public class CustomResolver : DefaultContractResolver
{
    private Dictionary<Type, JsonConverter> Converters { get; set; }

    public CustomResolver(Dictionary<Type, JsonConverter> converters)
    {
        Converters = converters;
    }

    protected override JsonObjectContract CreateObjectContract(Type objectType)
    {
        JsonObjectContract contract = base.CreateObjectContract(objectType);
        if (Converters.TryGetValue(objectType, out JsonConverter converter))
        {
            contract.Converter = converter;
        }
        return contract;
    }
}

Then, when you wanted to use the AlternativeConverter in place of the BaseJsonConverter , you could use the custom resolver like this:然后,当您想使用AlternativeConverter代替BaseJsonConverter ,您可以像这样使用自定义解析器:

// map the `Author` type to the `AlternativeConverter`
var converters = new Dictionary<Type, JsonConverter>()
{
    { typeof(Author), new AlternativeConverter() }
};

// Create a resolver with the converter mapping and add it to the serializer settings
var settings = new JsonSerializerSettings
{
    ContractResolver = new CustomResolver(converters)
};

// Use the settings when deserializing
var author = JsonConvert.DeserializeObject<Author>(jsonString, settings);

Demo Fiddle: https://dotnetfiddle.net/cu0igV演示小提琴: https : //dotnetfiddle.net/cu0igV


Of course, if all you're really doing with these converters is remapping properties to different names, you could just use a ContractResolver for that in the first place and get rid of the converters altogether.当然,如果您真正使用这些转换器所做的只是将属性重新映射到不同的名称,那么您可以首先使用ContractResolver并完全摆脱转换器。 See Json.NET deserialize or serialize json string and map properties to different property names defined at runtime for more information on that approach.有关该方法的更多信息,请参阅Json.NET 反序列化或序列化 json 字符串并将属性映射到在运行时定义的不同属性名称

I think you should try to use different JsonSerializerSettings instances for different data sources, with different Converters collections.我认为您应该尝试为不同的数据源使用不同的JsonSerializerSettings实例,以及不同的Converters集合。 And remove JsonConverter attributes from your classes.并从您的类中删除JsonConverter属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Json.NET如何覆盖通过属性定义自定义JsonConverter的类型的序列化? - Json.NET how to override serialization for a type that defines a custom JsonConverter via an attribute? 自定义JsonConverter作为属性 - Custom JsonConverter as Attribute 基于自定义属性的 JsonConverter - JsonConverter based on custom attribute JsonConverter 不能作为属性属性工作 - JsonConverter not working as property attribute 通过属性应用时如何将多个参数传递给 JsonConverter? - How to pass multiple arguments to a JsonConverter when applied via an attribute? 如何在自定义 System.Text.Json JsonConverter 中使用默认序列化? - How to use default serialization in a custom System.Text.Json JsonConverter? 使用JsonConverter的Json.NET自定义序列化-如何获得“默认”行为 - Json.NET custom serialization with JsonConverter - how to get the “default” behavior 具有DependencyInjection的C#JsonConverter属性 - c# JsonConverter Attribute with DependencyInjection 如何在JsonConverter中的自定义WriteJson中保留$ id和$ type之类的默认Json.Net字段? - How do I preserve default Json.Net fields like $id and $type in a custom WriteJson in JsonConverter? 无法应用属性类&#39;JsonConverter&#39;,因为它是抽象的 - Cannot apply attribute class 'JsonConverter' because it is abstract
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM