System.Text.Json:如何像常规类一样序列化 IEnumerable?

Dam*_*les 5 .net system.text.json

似乎如果一个对象是 an IEnumerable,Json 会忽略它的字段并序列化可枚举。例如,对于如下所示的类,Title未序列化。我发现了几乎相同的问题,答案是添加[JsonObject]到类中,但它是关于使用 Newtonsoft.Json 的,我正在通过 .NET 7.0 的 Json 使用JsonResult。.NET Json 有等效的东西吗?

        var myBook = new Book()
        {
            Title = "Jane Eyre",
            Pages = new List<string>() { "page1", "page2", "page3" }
        };
        var options = new JsonSerializerOptions { IncludeFields = true };
        return new JsonResult(myBook, options);
    }

    public class Book:IEnumerable<string>
    {
        public string Title;
        public IList<string> Pages;

        public IEnumerator<string> GetEnumerator()
        {
            return Pages.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return Pages.GetEnumerator() as IEnumerator;
        }
    }
Run Code Online (Sandbox Code Playgroud)

Orw*_*wel 2

实际上不是,但已要求这样做:

为序列化程序提供选项,将 IEnumerables 视为具有成员的对象#1808

System.Text.Json有转换器JsonObjectConverter有可以完成这项工作的

在未来的 .NET 版本中,将公开内部转换器:

开发人员应该有权访问 System.Text.Json 的默认内部转换器#63791

之后,您将可以:

[JsonConverter(typeof(JsonObjectConverter))]
public class Book:IEnumerable<string>
{...}
Run Code Online (Sandbox Code Playgroud)

目前,解决方法是为每种IEnumerable类型编写一个转换器,例如:

public class BookConverter : Json.Serialization.JsonConverter<Book>
{
    public override Book? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        if (reader.TokenType != JsonTokenType.StartObject)
        {
            throw new JsonException();
        }

        var obj = new Book();
        do
        {
            reader.Read();

            if (reader.TokenType == JsonTokenType.PropertyName)
            {
                string propName = reader.GetString();
                reader.Read();

                switch(propName)
                {
                    case "Title":
                        obj.Title = reader.GetString();
                        break;
                    case "Pages":
                        obj.Pages = JsonSerializer.Deserialize<IList<string>>(ref reader, options);
                        break;
                    default:
                        throw new JsonException();
                }
            }
            else if (reader.TokenType == JsonTokenType.EndObject)
            {
                break;
            }
        } while (true);

        return obj;
    }

    public override void Write(Utf8JsonWriter writer, Book value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();
        writer.WriteString("Title", value.Title);
        writer.WritePropertyName("Pages");
        JsonSerializer.Serialize(writer, value.Pages, options);
        writer.WriteEndObject();
    }
}
Run Code Online (Sandbox Code Playgroud)