将C#列表序列化为具有内部数组的复数命名对象
我们有一个遗留的WCF产品,它使用XML序列化属性序列化POCO 下面是一个列表示例,具有XmlArray/XmlArrayItem属性。 有点像[ 现在,我们有了一个.NETCore2.1应用程序,没有XML输出,只有Json。 所以我想将列表序列化到这个Json响应中,这样我就不会破坏任何期待这个响应的客户机 我意识到我可以围绕列表编写一个包装器,但我有大约40个列表要做,调用代码会变得非常模糊。 事实上,如果我执行“粘贴特殊”>“将JSON粘贴为类”,它看起来像:将C#列表序列化为具有内部数组的复数命名对象,c#,json,xml,serialization,asp.net-core-2.1,C#,Json,Xml,Serialization,Asp.net Core 2.1,我们有一个遗留的WCF产品,它使用XML序列化属性序列化POCO 下面是一个列表示例,具有XmlArray/XmlArrayItem属性。 有点像[ 现在,我们有了一个.NETCore2.1应用程序,没有XML输出,只有Json。 所以我想将列表序列化到这个Json响应中,这样我就不会破坏任何期待这个响应的客户机 我意识到我可以围绕列表编写一个包装器,但我有大约40个列表要做,调用代码会变得非常模糊。 事实上,如果我执行“粘贴特殊”>“将JSON粘贴为类”,它看起来像: class Mode
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)
基于-我已经尝试过这个JsonConverter。
但结果是这样的,反过来说,我需要对象和数组
{
"things": [
{
"thing": {
"Id": 1
}
},
{
"thing": {
"Id": 2
}
}
]
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用Newtonsoft.Json;
使用Newtonsoft.Json.Linq;
公共课程
{
公共静态void Main()
{
var foo=new foo();
foo.Things=newlist{newfoo.Things{Id=1},newfoo.Things{Id=2};
WriteLine(JsonConvert.SerializeObject(foo,Formatting.Indented));
}
}
福班
{
[JsonProperty(“事物”)]
[JsonConverter(typeof(CustomArrayConverter),“thing”)]
公开物品清单
{
得到;
设置
}
公共类事物
{
公共整数Id
{
得到;
设置
}
}
}
类CustomArrayConverter:JsonConverter
{
字符串属性名称
{
得到;
设置
}
公共CustomArrayConverter(字符串属性名称)
{
PropertyName=PropertyName;
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
JArray数组=新的JArray(JArray.Load(reader.Select)(jo=>jo[PropertyName]);
返回array.ToObject(objectType,序列化程序);
}
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
IEnumerable项=(IEnumerable)值;
JArray数组=新的JArray(items.Select(i=>newJobject)(新的JProperty(PropertyName,JToken.FromObject(i,serializer')));
array.WriteTo(writer);
}
公共覆盖布尔CanConvert(类型objectType)
{
//使用[JsonConverter]属性时不调用CanConvert
返回false;
}
}
感谢@Brian on,他为我指明了正确的方向
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;
}
}
类CustomArrayConverter:JsonConverter
{
字符串PropertyName{get;set;}
公共CustomArrayConverter(字符串属性名称)
{
PropertyName=PropertyName;
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
JArray数组=新的JArray(JArray.Load(reader.Select)(jo=>jo[PropertyName]);
返回array.ToObject(objectType,序列化程序);
}
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
IEnumerable项=(IEnumerable)值;
JObject-JObject=new-JObject(new-JProperty(PropertyName,new-JArray)(items.Select(i=>JToken.FromObject(i,serializer')));
jObject.WriteTo(writer);
}
公共覆盖布尔CanConvert(类型objectType)
{
//使用[JsonConverter]属性时不调用CanConvert
返回false;
}
}
您可以使用自定义的JsonConverter
——尽管CustomCreationConverter
不起作用。问题是内部属性“Thing”
的名称对于每个列表属性都不同,对吗?它当前由[XmlArrayItem(字符串名称)]
但是传递给构造函数的名称因属性而异,您打算如何保留该名称?是否继续使用XmlArrayItem
属性装饰属性?Thing-Internal属性将只设置一次(它是一个Thing数组)。请参阅上面的代码示例2。这不是我选择输出json的方式。但这正是我必须处理的。有没有关于如何使用JsonConverter的示例?谢谢,是的,我做了
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)
{
"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;
}
}
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;
}
}