将 C# 列表序列化为具有内部数组的复数命名对象
Posted
技术标签:
【中文标题】将 C# 列表序列化为具有内部数组的复数命名对象【英文标题】:Serialize C# List into plural named object with an inner array 【发布时间】:2020-04-09 16:01:38 【问题描述】:我们有一个旧的 WCF 产品,它使用 XML 序列化属性序列化 POCO。
这是一个 List 示例,具有 XmlArray/XmlArrayItem 属性。 有点像[How do I Set XmlArrayItem Element name for a List<Custom> implementation?
[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.ThingId = 1, new Foo.ThingId = 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;
【问题讨论】:
您可以使用自定义的JsonConverter
-- 尽管CustomCreationConverter
不起作用。问题是内部属性 "Thing"
的名称对于每个列表属性都会有所不同,对吧?它目前由[XmlArrayItem(string name)]
控制,但传递给构造函数的名称因属性而异,您打算如何保留该名称?你会继续用XmlArrayItem
属性装饰你的房产吗?
Thing 内部属性只会设置一次(它是一个 Thing 数组)。请参见上面的代码示例 2。这不是我选择输出 json 的方式。但这正是我必须使用的。如何使用 JsonConverter 的任何示例?
【参考方案1】:
感谢@Brian Name array elements in 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;
【讨论】:
谢谢,我做到了以上是关于将 C# 列表序列化为具有内部数组的复数命名对象的主要内容,如果未能解决你的问题,请参考以下文章
JavaScriptSerializer类 对象序列化为JSON,JSON反序列化为对象