如何使JsonConverterAttribute使用与JsonConvert.Deserialize函数相同的NamingStrategy。

huangapple go评论55阅读模式
英文:

How to get the JsonConverterAttribute to use the same NamingStrategy as the JsonConvert.Deserialize function

问题

以下是您提供的代码的翻译部分:

我有以下类用于序列化

```c#
class Container
{
    [JsonConverter(typeof(PropertyConverter))]
    public PropertyBase SomeProperty { get; set; }
}

它使用以下方式进行序列化

var settings = new JsonSerializerSettings
{
    ContractResolver = new DefaultContractResolver
    {
        NamingStrategy = new SnakeCaseNamingStrategy()
    }
};

var serialized = JsonConvert.SerializeObject(
    new Container
    {
        SomeProperty = new PropertyImplementationA
        {
            PropertyA = "some string value"
        }
    }, settings);

但是,当我使用以下方式进行反序列化

var deserialized = JsonConvert.DeserializeObject<Container>(settings);

转换器未被使用。

经过调查,如果我删除蛇形命名策略,一切都可以正常工作,因此看起来Newtonsoft在使用JsonConverterAttribute时,会为不同的命名策略注册属性名称上的转换器。

约束

作为一种解决方法,可以在序列化器设置中注册转换器,但在创建设置时并不总是知道要使用哪些转换器,对于这种情况来说,这不是可行的选项。

另一种解决方法是显式地使用[JsonProperty("property_base")]修饰属性,但这也不可行,因为我们需要在整个代码库中为属性添加修饰。

如果不指定蛇形命名策略,这将按预期工作,但是这个策略已经是代码库正在使用的,无法更改。

问题

如何使JsonConverterAttribute使用与传递给JsonConvert.DeserializeObject函数的JsonSerializerSettings相同的命名策略?

您可以在.NET Fiddle中运行一个可行示例,链接在这里

英文:

I have the following class to serialize

class Container
{
    [JsonConverter(typeof(PropertyConverter))]
    public PropertyBase SomeProperty { get; set; }
}

Which is serialized with

var settings = new JsonSerializerSettings
{
    ContractResolver = new DefaultContractResolver
    {
        NamingStrategy = new SnakeCaseNamingStrategy()
    }
}:

var serialized = JsonConvert.SerializeObject(
    new Container
    {
        SomeProperty = new PropertyImplementationA
        {
            PropertyA = &quot;some string value&quot;
        }
    }, settings);

but when I deserialize with

var deserialized = JsonConvert.DeserializeObject&lt;Container&gt;(settings);

The converter is not used.

On investigation, if I remove the sname case naming strategy it all works so it appears that Newtonsoft is registering the the converter to the property name with a different naming strategy when using the JsonConverterAttibute.

Constraints

As a workaround one can register the converters with the serializer settings I won't always know the converters to be used when the settings are created, that isn't a feasable option for this case.

As another workaround one can decorate the properties with [JsonProperty(&quot;property_base&quot;)] explicitly but this also isn't feasable as we would need to decorate properties all over the codebase.

This works as expected if one doesn't specify the SnameCaseNamingStrategy however this strategy is what the codebase already uses and can't be changed.

Question

How does one get the JsonConverterAttribute to use the same naming strategy as the JsonSerializerSettings passed to the JsonConvert.DeserializeObject function?

You can run a working example in .Net Fiddle here

答案1

得分: 2

看起来ContractResolver 给了 JsonConverter 一个优先级。我认为这可能是个好主意,否则很难预测结果。如果将合同解析器移到 JsonConverter 中,或者明确添加属性名称,一切都没问题。

一切都运行正常,当我在 JSON 转换器内部添加了合同解析器设置。在这种情况下,您不需要使用 JsonProperty 属性。我还让转换器变得更加简单。

ReadJson 方法如下:

override public PropertyBase? ReadJson(JsonReader reader, Type objectType, PropertyBase? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
    if (reader.TokenType == JsonToken.Null) return null;
    var settings = new JsonSerializerSettings
    {
        ContractResolver = new DefaultContractResolver
        {
            NamingStrategy = new SnakeCaseNamingStrategy()
        }
    };
    var jObject = JObject.Load(reader);
    return (PropertyBase)JsonConvert.DeserializeObject(jObject.ToString(), Type.GetType((string)jObject["type"]), settings);
}

类也可以更加简单,如下:

PropertyImplementationA 类如下:

class PropertyImplementationA : PropertyBase
{
    public string PropertyA { get; set; }
}

PropertyBase 抽象类如下:

abstract class PropertyBase
{
    public string Type
    {
        get { return this.GetType().Name; }
    }
}

还有更简单的方法,您可以使用 Newtonsoft.Json 的 SerializeTypeNameHandling 选项。详细信息请参考:https://www.newtonsoft.com/json/help/html/SerializeTypeNameHandling.htm

英文:

It seems that ContractResolver gives a priority to a JsonConverter. I
think maybe it is a good idea otherwise it would be hard to predict a result. If you move a contract resolver into a JsonConverter or add the property names explicitly everyting is ok

class Container
{
	[JsonConverter(typeof(PropertyConverter))]
	[JsonProperty(&quot;some_property&quot;)]
	public PropertyBase SomeProperty { get; set; }
}
class PropertyImplementationA : PropertyBase
{
	override public string Type =&gt; nameof(PropertyImplementationA);
    [JsonProperty(&quot;property_a&quot;)]
	public string PropertyA { get; set; }
}

Everything is working fine when I added contract resolver settings inside of the json converter. In this case you don't need JsonProperty attributes. I also made the converter much more simple

override public PropertyBase? ReadJson(JsonReader reader, Type objectType, PropertyBase? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
		if (reader.TokenType == JsonToken.Null) return null;
		var settings = new JsonSerializerSettings
		{
			ContractResolver = new DefaultContractResolver
			{
				NamingStrategy = new SnakeCaseNamingStrategy()
			}
		};
var jObject = JObject.Load(reader);
return (PropertyBase)JsonConvert.DeserializeObject(jObject.ToString(), 
Type.GetType((string)jObject[&quot;type&quot;]),settings);
}

and classes could be much more simple too

class PropertyImplementationA : PropertyBase
{
	public string PropertyA { get; set; }
}

abstract class PropertyBase
{
	public string Type
	{
		get { return this.GetType().Name; }
	}
}

and even more simple , you can use SerializeTypeNameHandling option of Newtonsoft.Json https://www.newtonsoft.com/json/help/html/SerializeTypeNameHandling.htm

huangapple
  • 本文由 发表于 2023年3月9日 20:09:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/75684423.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定