使用 System.Text.Json 时,有没有办法在对象上 return 自定义 JSON 结构?
Is there a way to return a custom JSON structure on an object when using System.Text.Json?
我正在编写不公开任何 public 属性的 class (AttributeBag)。在内部,我有一个通过 Get 和 Set 方法管理的对象(属性)列表。我希望能够在 AttributeBag class 上 运行 JsonSerializer.Serialize() 并检索如下所示的 JSON 结构:
[
{
"Name": "x",
"Value": "y"
},
{
"Name": "x1",
"Value": "y1"
},
{
"Name": "x2",
"Value": "y2"
}
]
我的 Attribute 和 AttributeBag class看起来像这样:
public class Attribute
{
public string Name { get; set; }
public object Value { get; set; }
}
public class AttributeBag
{
private readonly List<Attribute> attributes;
public AttributeBag()
{
this.attributes = new List<Attribute>();
}
public AttributeBag Set(string name, object value)
{
var searchAttribute = this.attributes.Find(x => x.Name.Equals(name));
if (searchAttribute != null)
{
searchAttribute.Value = value;
}
else
{
this.attributes.Add(new Attribute { Name = name, Value = value });
}
return this;
}
public Attribute Get(string name)
{
var searchAttribute = this.attributes.Find(x => x.Name.Equals(name));
if (searchAttribute != null)
{
return searchAttribute;
}
else
{
throw new AttributeNameNotFoundException(name);
}
}
public object GetValue(string name)
{
var searchAttribute = this.attributes.Find(x => x.Name.Equals(name));
if (searchAttribute != null)
{
return searchAttribute.Value;
}
else
{
throw new AttributeNameNotFoundException(name);
}
}
}
我希望能够像这样简单地做一些事情:
var ab = new AttributeBag();
ab.Set("x", "y");
ab.Set("x1", "y1");
ab.Set("x2", "y2");
string jsonData = JsonSerializer.Serialize(ab);
我尝试查看文档,但不确定如何继续上述操作。我应该为此使用 Utf8JsonWriter 吗?看来,如果我使用 Utf8JsonWriter,我将需要一个实现 JSON 编写的函数,并使用 ab.Serialize() 调用它,而不需要直接使用 JsonSerializer。那是要走的路还是有办法使用 JsonSerializer.Serialize?
如有指点,将不胜感激!
如果您正在使用 Newtonsoft.Json
,您可以像这样使用自定义 JsonConverter
using Newtonsoft.Json;
using System.Collections.Generic;
[JsonConverter(typeof(AttributeBagConverter))]
public class AttributeBag
{
//private constructor to make it able to create instance from converter
private AttributeBag(List<Attribute> attributes)
{
this.attributes = attributes;
}
public class AttributeBagConverter : JsonConverter<AttributeBag>
{
public override AttributeBag ReadJson(JsonReader reader, System.Type objectType,
AttributeBag existingValue, bool hasExistingValue, JsonSerializer serializer)
{
//deserialize as List<Attribute> and pass results to private constructor
return new AttributeBag(serializer.Deserialize<List<Attribute>>(reader));
}
public override void WriteJson(JsonWriter writer, AttributeBag value,
JsonSerializer serializer)
{
//serialize List<Attribute> only
serializer.Serialize(writer, value.attributes);
}
}
/* rest of your code */
}
as you can see 它以您想要的方式序列化和反序列化您的对象
感谢 Sushant Yelpale 的提示和评论中的 link,我成功实现了如下自定义序列化。
我创建了一个新转换器class AttributeBagConverter:
class AttributeBagConverter : JsonConverter<AttributeBag>
{
public override bool CanConvert(Type typeToConvert)
{
return true;
}
public override AttributeBag Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
public override void Write(Utf8JsonWriter writer, AttributeBag value, JsonSerializerOptions options)
{
writer.WriteStartArray();
if (value.Count > 0)
{
foreach (var item in value)
{
writer.WriteStartObject();
writer.WritePropertyName("Name");
writer.WriteStringValue(item.Name);
writer.WritePropertyName("Value");
if (double.TryParse(item.Value.ToString(), out double n))
{
writer.WriteNumberValue(n);
}
else
{
writer.WriteStringValue(item.Value.ToString());
}
writer.WriteEndObject();
}
}
writer.WriteEndArray();
writer.Flush();
}
}
然后我用 JsonConverter(typeof(AttributeBagConverter))
:
装饰了我的 AttributeBag class
[JsonConverter(typeof(AttributeBagConverter))]
public class AttributeBag: IEnumerable<Attribute>
{
private readonly List<Attribute> attributes;
public int Count
{
get
{
return this.attributes.Count;
}
}
public AttributeBag()
{
this.attributes = new List<Attribute>();
}
public AttributeBag Set(string name, object value)
{
var searchAttribute = this.attributes.Find(x => x.Name.Equals(name));
if (searchAttribute != null)
{
searchAttribute.Value = value;
}
else
{
this.attributes.Add(new Attribute { Name = name, Value = value });
}
return this;
}
public Attribute Get(string name)
{
var searchAttribute = this.attributes.Find(x => x.Name.Equals(name));
if (searchAttribute != null)
{
return searchAttribute;
}
else
{
throw new AttributeNameNotFoundException(name);
}
}
public object GetValue(string name)
{
var searchAttribute = this.attributes.Find(x => x.Name.Equals(name));
if (searchAttribute != null)
{
return searchAttribute.Value;
}
else
{
throw new AttributeNameNotFoundException(name);
}
}
public IEnumerator<Attribute> GetEnumerator()
{
return this.attributes.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
现在正在对象上调用 JsonSerializer.Serialize() returns 我正在寻找的正确 JSON 格式!
我正在编写不公开任何 public 属性的 class (AttributeBag)。在内部,我有一个通过 Get 和 Set 方法管理的对象(属性)列表。我希望能够在 AttributeBag class 上 运行 JsonSerializer.Serialize() 并检索如下所示的 JSON 结构:
[
{
"Name": "x",
"Value": "y"
},
{
"Name": "x1",
"Value": "y1"
},
{
"Name": "x2",
"Value": "y2"
}
]
我的 Attribute 和 AttributeBag class看起来像这样:
public class Attribute
{
public string Name { get; set; }
public object Value { get; set; }
}
public class AttributeBag
{
private readonly List<Attribute> attributes;
public AttributeBag()
{
this.attributes = new List<Attribute>();
}
public AttributeBag Set(string name, object value)
{
var searchAttribute = this.attributes.Find(x => x.Name.Equals(name));
if (searchAttribute != null)
{
searchAttribute.Value = value;
}
else
{
this.attributes.Add(new Attribute { Name = name, Value = value });
}
return this;
}
public Attribute Get(string name)
{
var searchAttribute = this.attributes.Find(x => x.Name.Equals(name));
if (searchAttribute != null)
{
return searchAttribute;
}
else
{
throw new AttributeNameNotFoundException(name);
}
}
public object GetValue(string name)
{
var searchAttribute = this.attributes.Find(x => x.Name.Equals(name));
if (searchAttribute != null)
{
return searchAttribute.Value;
}
else
{
throw new AttributeNameNotFoundException(name);
}
}
}
我希望能够像这样简单地做一些事情:
var ab = new AttributeBag();
ab.Set("x", "y");
ab.Set("x1", "y1");
ab.Set("x2", "y2");
string jsonData = JsonSerializer.Serialize(ab);
我尝试查看文档,但不确定如何继续上述操作。我应该为此使用 Utf8JsonWriter 吗?看来,如果我使用 Utf8JsonWriter,我将需要一个实现 JSON 编写的函数,并使用 ab.Serialize() 调用它,而不需要直接使用 JsonSerializer。那是要走的路还是有办法使用 JsonSerializer.Serialize?
如有指点,将不胜感激!
如果您正在使用 Newtonsoft.Json
,您可以像这样使用自定义 JsonConverter
using Newtonsoft.Json;
using System.Collections.Generic;
[JsonConverter(typeof(AttributeBagConverter))]
public class AttributeBag
{
//private constructor to make it able to create instance from converter
private AttributeBag(List<Attribute> attributes)
{
this.attributes = attributes;
}
public class AttributeBagConverter : JsonConverter<AttributeBag>
{
public override AttributeBag ReadJson(JsonReader reader, System.Type objectType,
AttributeBag existingValue, bool hasExistingValue, JsonSerializer serializer)
{
//deserialize as List<Attribute> and pass results to private constructor
return new AttributeBag(serializer.Deserialize<List<Attribute>>(reader));
}
public override void WriteJson(JsonWriter writer, AttributeBag value,
JsonSerializer serializer)
{
//serialize List<Attribute> only
serializer.Serialize(writer, value.attributes);
}
}
/* rest of your code */
}
as you can see 它以您想要的方式序列化和反序列化您的对象
感谢 Sushant Yelpale 的提示和评论中的 link,我成功实现了如下自定义序列化。
我创建了一个新转换器class AttributeBagConverter:
class AttributeBagConverter : JsonConverter<AttributeBag>
{
public override bool CanConvert(Type typeToConvert)
{
return true;
}
public override AttributeBag Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
public override void Write(Utf8JsonWriter writer, AttributeBag value, JsonSerializerOptions options)
{
writer.WriteStartArray();
if (value.Count > 0)
{
foreach (var item in value)
{
writer.WriteStartObject();
writer.WritePropertyName("Name");
writer.WriteStringValue(item.Name);
writer.WritePropertyName("Value");
if (double.TryParse(item.Value.ToString(), out double n))
{
writer.WriteNumberValue(n);
}
else
{
writer.WriteStringValue(item.Value.ToString());
}
writer.WriteEndObject();
}
}
writer.WriteEndArray();
writer.Flush();
}
}
然后我用 JsonConverter(typeof(AttributeBagConverter))
:
[JsonConverter(typeof(AttributeBagConverter))]
public class AttributeBag: IEnumerable<Attribute>
{
private readonly List<Attribute> attributes;
public int Count
{
get
{
return this.attributes.Count;
}
}
public AttributeBag()
{
this.attributes = new List<Attribute>();
}
public AttributeBag Set(string name, object value)
{
var searchAttribute = this.attributes.Find(x => x.Name.Equals(name));
if (searchAttribute != null)
{
searchAttribute.Value = value;
}
else
{
this.attributes.Add(new Attribute { Name = name, Value = value });
}
return this;
}
public Attribute Get(string name)
{
var searchAttribute = this.attributes.Find(x => x.Name.Equals(name));
if (searchAttribute != null)
{
return searchAttribute;
}
else
{
throw new AttributeNameNotFoundException(name);
}
}
public object GetValue(string name)
{
var searchAttribute = this.attributes.Find(x => x.Name.Equals(name));
if (searchAttribute != null)
{
return searchAttribute.Value;
}
else
{
throw new AttributeNameNotFoundException(name);
}
}
public IEnumerator<Attribute> GetEnumerator()
{
return this.attributes.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
现在正在对象上调用 JsonSerializer.Serialize() returns 我正在寻找的正确 JSON 格式!