C# - 在 JSON 序列化和反序列化之间设置不同的 PropertyName
C# - Set different PropertyName between JSON serialization and deserialization
我正在查询 API,响应是自定义的 JSON。在网上查看后,我设法通过这种方式将其反序列化为自定义对象:
Post.cs
[JsonConverter(typeof(JsonPathConverter))]
public class Post
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "taken_at_timestamp")]
public long Timestamp { get; set; }
[JsonProperty(PropertyName = "edge_media_preview_like.count")]
public int LikeCount { get; set; }
[JsonProperty(PropertyName = "edge_media_to_comment.count")]
public int CommentCount { get; set; }
[JsonProperty(PropertyName = "edge_media_to_caption.edges[0].node.text")]
public string Caption { get; set; }
[JsonProperty(PropertyName = "display_url")]
public string Image { get; set; }
[JsonProperty(PropertyName = "dimensions.width")]
public int Width { get; set; }
[JsonProperty(PropertyName = "dimensions.height")]
public int Height { get; set; }
[JsonProperty(PropertyName = "shortcode")]
public string Shortcode { get; set; }
}
JsonPathConverter.cs
public class JsonPathConverter : JsonConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
object targetObj = Activator.CreateInstance(objectType);
foreach (PropertyInfo prop in objectType.GetProperties().Where(p => p.CanRead && p.CanWrite))
{
JsonPropertyAttribute att = prop.GetCustomAttributes(true)
.OfType<JsonPropertyAttribute>()
.FirstOrDefault();
string jsonPath = (att != null ? att.PropertyName : prop.Name);
JToken token = jo.SelectToken(jsonPath);
if (token != null && token.Type != JTokenType.Null)
{
object value = token.ToObject(prop.PropertyType, serializer);
prop.SetValue(targetObj, value, null);
}
}
return targetObj;
}
public override bool CanConvert(Type objectType)
{
return false;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
问题是当我想将该对象作为 JSON 发送时:它 returns 字段具有 PropertyName 值,而不是属性名称:
[
{
"id": "2322829435103312153",
"taken_at_timestamp": 1591122868,
"edge_media_preview_like.count": 24,
"edge_media_to_comment.count": 0,
"edge_media_to_caption.edges[0].node.text": "...",
"display_url": "...",
"dimensions.width": 1080,
"dimensions.height": 1080,
"shortcode": "..."
}
...
]
有没有办法使用 PropertyName 进行反序列化,而使用属性名称进行序列化?
更新
应要求,我是这样使用反序列化和序列化的:
反序列化
JArray response = "[{ ... }]";
List<Post> posts = new List<Post>();
foreach (JObject node in response)
{
Post post = JsonConvert.DeserializeObject<Post>(node.ToString());
posts.Add(post);
}
序列化
我只是 return List 里面的一个“Ok” IActionResult:
Ok(posts);
您可以使用 ContractResolver
如下所示。
var jsondata = JsonConvert.SerializeObject(data, new JsonSerializerSettings { ContractResolver = new ShouldUseMemberNameContractResolver() });
public class ShouldUseMemberNameContractResolver : DefaultContractResolver
{
public new static readonly ShouldUseMemberNameContractResolver Instance = new ShouldUseMemberNameContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.DeclaringType == typeof(Post))
{
property.PropertyName = member.Name;
}
return property;
}
}
我按照Chetan Ranpariya的建议通过WriteJson方法解决了:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JArray result = new JArray();
if (value.GetType().IsGenericType && value is IEnumerable)
{
IEnumerable list = value as IEnumerable;
foreach(var obj in list)
{
result.Add(GetObjectJson(obj));
}
}
result.WriteTo(writer);
}
private JObject GetObjectJson(object obj)
{
JObject jObj = new JObject();
PropertyInfo[] props = obj.GetType().GetProperties();
foreach (PropertyInfo prop in props)
{
if (!prop.PropertyType.ToString().Contains("System"))
jObj.Add(char.ToLowerInvariant(prop.Name[0]) + prop.Name.Substring(1), GetObjectJson(prop.GetValue(obj)));
else
jObj.Add(char.ToLowerInvariant(prop.Name[0]) + prop.Name.Substring(1), JToken.FromObject(prop.GetValue(obj)));
}
return jObj;
}
与 object value
参数一样,我收到对象(在本例中是一个列表),我对其进行转换并遍历它的对象。
由于每个对象都可以具有原始属性和非原始属性,因此我创建了一个单独的函数来递归使用它,以防发现嵌套对象。
我正在查询 API,响应是自定义的 JSON。在网上查看后,我设法通过这种方式将其反序列化为自定义对象:
Post.cs
[JsonConverter(typeof(JsonPathConverter))]
public class Post
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "taken_at_timestamp")]
public long Timestamp { get; set; }
[JsonProperty(PropertyName = "edge_media_preview_like.count")]
public int LikeCount { get; set; }
[JsonProperty(PropertyName = "edge_media_to_comment.count")]
public int CommentCount { get; set; }
[JsonProperty(PropertyName = "edge_media_to_caption.edges[0].node.text")]
public string Caption { get; set; }
[JsonProperty(PropertyName = "display_url")]
public string Image { get; set; }
[JsonProperty(PropertyName = "dimensions.width")]
public int Width { get; set; }
[JsonProperty(PropertyName = "dimensions.height")]
public int Height { get; set; }
[JsonProperty(PropertyName = "shortcode")]
public string Shortcode { get; set; }
}
JsonPathConverter.cs
public class JsonPathConverter : JsonConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject jo = JObject.Load(reader);
object targetObj = Activator.CreateInstance(objectType);
foreach (PropertyInfo prop in objectType.GetProperties().Where(p => p.CanRead && p.CanWrite))
{
JsonPropertyAttribute att = prop.GetCustomAttributes(true)
.OfType<JsonPropertyAttribute>()
.FirstOrDefault();
string jsonPath = (att != null ? att.PropertyName : prop.Name);
JToken token = jo.SelectToken(jsonPath);
if (token != null && token.Type != JTokenType.Null)
{
object value = token.ToObject(prop.PropertyType, serializer);
prop.SetValue(targetObj, value, null);
}
}
return targetObj;
}
public override bool CanConvert(Type objectType)
{
return false;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
问题是当我想将该对象作为 JSON 发送时:它 returns 字段具有 PropertyName 值,而不是属性名称:
[
{
"id": "2322829435103312153",
"taken_at_timestamp": 1591122868,
"edge_media_preview_like.count": 24,
"edge_media_to_comment.count": 0,
"edge_media_to_caption.edges[0].node.text": "...",
"display_url": "...",
"dimensions.width": 1080,
"dimensions.height": 1080,
"shortcode": "..."
}
...
]
有没有办法使用 PropertyName 进行反序列化,而使用属性名称进行序列化?
更新
应要求,我是这样使用反序列化和序列化的:
反序列化
JArray response = "[{ ... }]";
List<Post> posts = new List<Post>();
foreach (JObject node in response)
{
Post post = JsonConvert.DeserializeObject<Post>(node.ToString());
posts.Add(post);
}
序列化
我只是 return List 里面的一个“Ok” IActionResult:
Ok(posts);
您可以使用 ContractResolver
如下所示。
var jsondata = JsonConvert.SerializeObject(data, new JsonSerializerSettings { ContractResolver = new ShouldUseMemberNameContractResolver() });
public class ShouldUseMemberNameContractResolver : DefaultContractResolver
{
public new static readonly ShouldUseMemberNameContractResolver Instance = new ShouldUseMemberNameContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.DeclaringType == typeof(Post))
{
property.PropertyName = member.Name;
}
return property;
}
}
我按照Chetan Ranpariya的建议通过WriteJson方法解决了:
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JArray result = new JArray();
if (value.GetType().IsGenericType && value is IEnumerable)
{
IEnumerable list = value as IEnumerable;
foreach(var obj in list)
{
result.Add(GetObjectJson(obj));
}
}
result.WriteTo(writer);
}
private JObject GetObjectJson(object obj)
{
JObject jObj = new JObject();
PropertyInfo[] props = obj.GetType().GetProperties();
foreach (PropertyInfo prop in props)
{
if (!prop.PropertyType.ToString().Contains("System"))
jObj.Add(char.ToLowerInvariant(prop.Name[0]) + prop.Name.Substring(1), GetObjectJson(prop.GetValue(obj)));
else
jObj.Add(char.ToLowerInvariant(prop.Name[0]) + prop.Name.Substring(1), JToken.FromObject(prop.GetValue(obj)));
}
return jObj;
}
与 object value
参数一样,我收到对象(在本例中是一个列表),我对其进行转换并遍历它的对象。
由于每个对象都可以具有原始属性和非原始属性,因此我创建了一个单独的函数来递归使用它,以防发现嵌套对象。