C# 使用System.Text.JSON时,是否有方法返回对象上的自定义JSON结构?

C# 使用System.Text.JSON时,是否有方法返回对象上的自定义JSON结构?,c#,.net,json,serialization,system.text.json,C#,.net,Json,Serialization,System.text.json,我正在编写一个不公开任何公共属性的类(AttributeBag)。在内部,我有一个通过Get和Set方法管理的对象(属性)列表。我希望能够在AttributeBag类上运行JsonSerializer.Serialize(),并检索如下所示的JSON结构: [ { "Name": "x", "Value": "y" }, { "Name": "x1", "Value": "y1" }, { "Name": "x2", "Valu

我正在编写一个不公开任何公共属性的类(AttributeBag)。在内部,我有一个通过Get和Set方法管理的对象(属性)列表。我希望能够在AttributeBag类上运行JsonSerializer.Serialize(),并检索如下所示的JSON结构:

[
  {
    "Name": "x",
    "Value": "y"
  },
  {
    "Name": "x1",
    "Value": "y1"
  },
  {
    "Name": "x2",
    "Value": "y2"
  }
]
我的属性和AttributeBag类如下所示:

public class Attribute
{
    public string Name { get; set; }
    public object Value { get; set; }
}
我试图查看文档,但不确定如何继续进行上述操作。我应该为此使用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 */
}
使用Newtonsoft.Json;
使用System.Collections.Generic;
[JsonConverter(类型(AttributeBagConverter))]
公共类属性包
{
//私有构造函数,使其能够从转换器创建实例

private AttributeBag(列出它以您想要的方式序列化和反序列化您的对象

感谢Sushant Yelpale在注释中提供的提示和链接,我成功地实现了自定义序列化,如下所示

我创建了一个新的转换器类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();
    }
}

调用JsonSerializer.Serialize()在对象上,现在返回我正在寻找的正确JSON格式!

以序列化JsonConverter类的JSON override WriteJson方法,感谢您提供的详细信息!我实际上使用的是System.Text.JSON而不是Newtonsoft.JSON。我根据上一条注释中的链接实现了一个解决方案。您的实现接近于我希望在Newtonsoft和Microsoft的JSON实现之间找到相似之处。
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 */
}
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))]
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();
    }
}