英文:
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 = "some string value"
}
}, settings);
but when I deserialize with
var deserialized = JsonConvert.DeserializeObject<Container>(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("property_base")]
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("some_property")]
public PropertyBase SomeProperty { get; set; }
}
class PropertyImplementationA : PropertyBase
{
override public string Type => nameof(PropertyImplementationA);
[JsonProperty("property_a")]
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["type"]),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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论