c# - 将 C# 列表序列化为具有内部数组的复数命名对象
问题描述
我们有一个遗留的 WCF 产品,它使用 XML 序列化属性序列化 POCO。
这是一个列表示例,具有 XmlArray/XmlArrayItem 属性。有点像 [如何为 List<Custom> 实现设置 XmlArrayItem 元素名称?
[XmlArray("Things", Order = 4), XmlArrayItem("Thing")]
public List<Thing> Things { get; set; }
这会产生 XML 响应:
<m:Things>
<m:Thing>
...
</m:Thing>
<m:Thing>
...
</m:Thing>
<m:Thing>
...
</m:Thing>
</m:Things>
并且(通过外部翻译)转换为此 Json 响应(具有内部数组(单数命名)Json 响应的复数命名对象):
"Things": {
"Thing": [
{
...
},
{
...
}
]}
现在,我们有一个没有 XML 输出的 .NET Core 2.1 应用程序 - 只有 Json。所以我想将 List 序列化到这个 Json 响应中,这样我就不会破坏任何期望这个响应的客户端。
我意识到我可以围绕 List 编写一个包装器,但我有大约 40 个这样的 List 要做,并且调用代码会变得非常模糊。事实上,如果我将选择性粘贴 > 粘贴 JSON 作为类,它看起来像:
class Model
{
public ThingsWrapper Things { get; set; }
}
public class ThingsWrapper
{
public Thing[] Thing { get; set; }
}
public class Thing
{
...
}
called with var x = Things.Thing; // (yuck)
基于https://dotnetfiddle.net/vUQKV1 - 我试过这个 JsonConverter。然而,结果是这样的,这是另一种方式。我需要事物作为对象,事物作为数组。
{
"things": [
{
"thing": {
"Id": 1
}
},
{
"thing": {
"Id": 2
}
}
]
}
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public class Program
{
public static void Main()
{
var foo = new Foo();
foo.Things = new List<Foo.Thing>{new Foo.Thing{Id = 1}, new Foo.Thing{Id = 2}};
Console.WriteLine(JsonConvert.SerializeObject(foo, Formatting.Indented));
}
}
class Foo
{
[JsonProperty("things")]
[JsonConverter(typeof(CustomArrayConverter<Thing>), "thing")]
public List<Thing> Things
{
get;
set;
}
public class Thing
{
public int Id
{
get;
set;
}
}
}
class CustomArrayConverter<T> : JsonConverter
{
string PropertyName
{
get;
set;
}
public CustomArrayConverter(string propertyName)
{
PropertyName = propertyName;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JArray array = new JArray(JArray.Load(reader).Select(jo => jo[PropertyName]));
return array.ToObject(objectType, serializer);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
IEnumerable<T> items = (IEnumerable<T>)value;
JArray array = new JArray(items.Select(i => new JObject(new JProperty(PropertyName, JToken.FromObject(i, serializer)))));
array.WriteTo(writer);
}
public override bool CanConvert(Type objectType)
{
// CanConvert is not called when the [JsonConverter] attribute is used
return false;
}
}
解决方案
感谢@Brian在 Json.NET 中命名数组元素? https://dotnetfiddle.net/vUQKV1,这为我指明了正确的方向。
class CustomArrayConverter<T> : JsonConverter
{
string PropertyName { get; set; }
public CustomArrayConverter(string propertyName)
{
PropertyName = propertyName;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JArray array = new JArray(JArray.Load(reader).Select(jo => jo[PropertyName]));
return array.ToObject(objectType, serializer);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
IEnumerable<T> items = (IEnumerable<T>)value;
JObject jObject = new JObject(new JProperty(PropertyName, new JArray(items.Select(i => JToken.FromObject(i, serializer)))));
jObject.WriteTo(writer);
}
public override bool CanConvert(Type objectType)
{
// CanConvert is not called when the [JsonConverter] attribute is used
return false;
}
}
推荐阅读
- python-3.x - 有没有办法根据现有 Excel 工作表上的数据创建迷你图?
- html - CSS 和页面大小调整
- python - Python 和 Excel 中某些矩阵的逆矩阵是不同的。我应该考虑哪些结果?
- python - 将文本列表分配给变量 python
- sql - SQL电子商务数据库。如何在同一行关联外键?
- dig - 解码挖掘输出:+norecurse @nameserver MX 到域
- windows - Windows 10 上的 Apache 2.4.46 虚拟主机
- c# - Blazor EditForm 以编程方式提交
- spring-boot - 在哪里可以找到 SpringBoot 包的 SHA256/SHA512 哈希?
- javascript - 如何将嵌入查询与 wordpress rest api 一起使用?