You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#类中定义以实现JSON重复字段名序列化

解决eBay API请求体序列化:重复字段而非数组的问题

嘿,我明白你的痛点——默认的JSON序列化会把集合转成数组,但eBay的API要求重复的outputSelector字段,而不是outputSelector[]数组。我来帮你搞定这个,顺便给你的代码提些符合C#规范的改进建议。

核心问题分析

大多数JSON序列化库(比如Newtonsoft.Json或System.Text.Json)默认会把List<T>/数组序列化为JSON数组,但eBay的这个API格式要求多个同名的顶级字段。所以我们需要自定义序列化逻辑,把集合里的每个元素都输出为独立的outputSelector键值对。

方案一:使用Newtonsoft.Json(最常用)

首先,我们先修正你的类结构(符合C#命名规范,改用属性而非字段),然后添加自定义转换器来处理outputSelector的序列化。

1. 自定义JSON转换器

这个转换器会把List<string>序列化为多个同名字段,同时兼容反序列化(如果需要的话):

using Newtonsoft.Json;
using System.Collections.Generic;
using System;

public class MultipleStringConverter : JsonConverter<List<string>>
{
    public override void WriteJson(JsonWriter writer, List<string> value, JsonSerializer serializer)
    {
        if (value == null || value.Count == 0)
            return;

        // 遍历列表,每个元素输出为独立的outputSelector字段
        foreach (var selector in value)
        {
            writer.WritePropertyName("outputSelector");
            serializer.Serialize(writer, selector);
        }
    }

    public override List<string> ReadJson(JsonReader reader, Type objectType, List<string> existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var selectors = new List<string>();
        
        // 兼容三种反序列化场景:数组、单个字符串、多个同名字段
        if (reader.TokenType == JsonToken.StartArray)
        {
            selectors = serializer.Deserialize<List<string>>(reader);
        }
        else if (reader.TokenType == JsonToken.String)
        {
            selectors.Add((string)reader.Value);
        }
        else if (reader.TokenType == JsonToken.PropertyName)
        {
            while (reader.TokenType == JsonToken.PropertyName && (string)reader.Value == "outputSelector")
            {
                reader.Read();
                selectors.Add((string)reader.Value);
                reader.Read();
            }
        }
        
        return selectors;
    }
}

2. 修正后的C#类结构

我调整了命名规范(帕斯卡命名法),把字段改成属性,添加了必要的JsonProperty属性映射JSON键名,并且初始化集合避免空引用:

using Newtonsoft.Json;
using System.Collections.Generic;

public class EbaySearchRequestBody
{
    [JsonProperty("findCompletedItemsRequest")]
    public FindCompletedItemsRequest FindCompletedItemsRequest { get; set; } = new FindCompletedItemsRequest();

    public class FindCompletedItemsRequest
    {
        [JsonProperty("keywords")]
        public string Keywords { get; set; }

        [JsonProperty("itemFilter")]
        public List<ItemFilter> ItemFilters { get; set; } = new List<ItemFilter>();

        [JsonProperty("sortOrder")]
        public string SortOrder { get; set; }

        [JsonProperty("paginationInput")]
        public PaginationInput PaginationInput { get; set; } = new PaginationInput();

        // 使用自定义转换器处理重复字段
        [JsonProperty("outputSelector")]
        [JsonConverter(typeof(MultipleStringConverter))]
        public List<string> OutputSelectors { get; set; } = new List<string>();
    }

    public class PaginationInput
    {
        [JsonProperty("entriesPerPage")]
        public string EntriesPerPage { get; set; }

        [JsonProperty("pageNumber")]
        public string PageNumber { get; set; }
    }

    public class ItemFilter
    {
        [JsonProperty("name")]
        public string Name { get; set; }

        [JsonProperty("value")]
        public string Value { get; set; }
    }
}

3. 序列化示例代码

// 构建请求体
var searchBody = new EbaySearchRequestBody();
searchBody.FindCompletedItemsRequest.Keywords = "searchtext";
searchBody.FindCompletedItemsRequest.ItemFilters.Add(new EbaySearchRequestBody.ItemFilter
{
    Name = "SoldItemsOnly",
    Value = "true"
});
// 添加多个outputSelector
searchBody.FindCompletedItemsRequest.OutputSelectors.Add("PictureURLLarge");
searchBody.FindCompletedItemsRequest.OutputSelectors.Add("SellerInfo");
searchBody.FindCompletedItemsRequest.PaginationInput.EntriesPerPage = "100";
searchBody.FindCompletedItemsRequest.PaginationInput.PageNumber = "1";

// 序列化JSON
var json = JsonConvert.SerializeObject(searchBody, Formatting.Indented);

这样生成的JSON就会和你期望的完全一致:

{
  "findCompletedItemsRequest": {
    "keywords": "searchtext",
    "itemFilter": [
      {
        "name": "SoldItemsOnly",
        "value": "true"
      }
    ],
    "sortOrder": null,
    "paginationInput": {
      "entriesPerPage": "100",
      "pageNumber": "1"
    },
    "outputSelector": "PictureURLLarge",
    "outputSelector": "SellerInfo"
  }
}

方案二:使用System.Text.Json(.NET Core/.NET 5+)

如果你用的是原生的System.Text.Json,也可以写类似的自定义转换器:

using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using System;

public class MultipleStringSystemTextJsonConverter : JsonConverter<List<string>>
{
    public override List<string> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var selectors = new List<string>();
        
        if (reader.TokenType == JsonTokenType.StartArray)
        {
            while (reader.Read() && reader.TokenType != JsonTokenType.EndArray)
            {
                if (reader.TokenType == JsonTokenType.String)
                    selectors.Add(reader.GetString());
            }
        }
        else if (reader.TokenType == JsonTokenType.String)
        {
            selectors.Add(reader.GetString());
        }
        else if (reader.TokenType == JsonTokenType.PropertyName)
        {
            while (reader.TokenType == JsonTokenType.PropertyName && reader.GetString() == "outputSelector")
            {
                reader.Read();
                if (reader.TokenType == JsonTokenType.String)
                    selectors.Add(reader.GetString());
                reader.Read();
            }
        }
        
        return selectors;
    }

    public override void Write(Utf8JsonWriter writer, List<string> value, JsonSerializerOptions options)
    {
        if (value == null || value.Count == 0)
            return;

        foreach (var selector in value)
        {
            writer.WriteString("outputSelector", selector);
        }
    }
}

然后在类的OutputSelectors属性上替换为:

[JsonPropertyName("outputSelector")]
[JsonConverter(typeof(MultipleStringSystemTextJsonConverter))]
public List<string> OutputSelectors { get; set; } = new List<string>();

序列化时使用:

var json = JsonSerializer.Serialize(searchBody, new JsonSerializerOptions { WriteIndented = true });

额外的代码改进建议

  • 命名规范:C#中类名、属性名推荐使用帕斯卡命名法(首字母大写),通过JsonProperty/JsonPropertyName映射到JSON的驼峰命名,既符合.NET惯例又满足API要求。
  • 避免空引用:初始化集合(ItemFilters、OutputSelectors)和嵌套对象(FindCompletedItemsRequest、PaginationInput)为新实例,防止后续赋值时出现NullReferenceException。
  • 类名语义化:把eBaySearchBody改成EbaySearchRequestBody,更清晰表达它的用途;itemFilters改成ItemFilter(单个过滤器),列表属性命名为ItemFilters,符合语义。

内容的提问来源于stack exchange,提问作者Fr45h3R

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:08:28