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

C#中如何处理支持两种不同类型取值的JSON字段

处理COCO格式多态Segmentation字段的实现方案

不需要使用object类型声明字段,直接通过自定义JSON转换器根据token类型自动匹配反序列化目标即可,全程保持类型安全,且完全兼容官方COCO标注格式规范,实现步骤如下:

1. 定义类型层级

首先定义专用抽象基类作为segmentation字段的静态类型,再分别实现两种格式的派生类,避免类型混淆:

public abstract class Segmentation
{
    // 可在此处添加公共辅助方法,比如掩码转换、面积计算等逻辑
}

// 多边形格式对应实现
public class PolygonSegmentation : Segmentation
{
    public List<List<float>> Polygons { get; set; } = [];
}

// RLE格式对应实现,复用已有的RLE结构定义
public class RleSegmentation : Segmentation
{
    [JsonProperty("size")]
    public List<int>? Size { get; set; }

    [JsonProperty("counts")]
    public List<int>? Counts { get; set; }
}

在标注类中,将segmentation字段声明为Segmentation类型,同时挂载自定义转换器:

public class CocoAnnotation
{
    [JsonProperty("id")]
    public int Id { get; set; }

    [JsonProperty("image_id")]
    public int ImageId { get; set; }

    [JsonProperty("category_id")]
    public int CategoryId { get; set; }

    [JsonProperty("segmentation")]
    [JsonConverter(typeof(SegmentationConverter))]
    public Segmentation Segmentation { get; set; } = null!;

    [JsonProperty("area")]
    public float Area { get; set; }

    [JsonProperty("bbox")]
    public List<float> Bbox { get; set; } = [];

    [JsonProperty("iscrowd")]
    public int IsCrowd { get; set; }
}

2. 实现自定义JSON转换器

核心判断逻辑:反序列化时先读取当前JSON token类型,数组类型匹配多边形格式,对象类型匹配RLE格式;序列化时根据传入的具体派生类型执行对应序列化逻辑。

Newtonsoft.Json 版本实现

public class SegmentationConverter : JsonConverter<Segmentation>
{
    public override Segmentation? ReadJson(JsonReader reader, Type objectType, Segmentation? existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var token = JToken.Load(reader);
        return token.Type switch
        {
            JTokenType.Array => new PolygonSegmentation
            {
                Polygons = token.ToObject<List<List<float>>>(serializer) ?? []
            },
            JTokenType.Object => token.ToObject<RleSegmentation>(serializer),
            _ => throw new JsonSerializationException($"非法的segmentation格式,token类型: {token.Type}")
        };
    }

    public override void WriteJson(JsonWriter writer, Segmentation? value, JsonSerializer serializer)
    {
        switch (value)
        {
            case PolygonSegmentation polygon:
                serializer.Serialize(writer, polygon.Polygons);
                break;
            case RleSegmentation rle:
                serializer.Serialize(writer, rle);
                break;
            default:
                throw new JsonSerializationException($"未知的Segmentation类型: {value?.GetType().FullName}");
        }
    }
}

System.Text.Json 版本实现

public class SegmentationSystemTextJsonConverter : JsonConverter<Segmentation>
{
    public override Segmentation? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return reader.TokenType switch
        {
            JsonTokenType.StartArray => new PolygonSegmentation
            {
                Polygons = JsonSerializer.Deserialize<List<List<float>>>(ref reader, options) ?? []
            },
            JsonTokenType.StartObject => JsonSerializer.Deserialize<RleSegmentation>(ref reader, options),
            _ => throw new JsonException($"非法的segmentation格式,token类型: {reader.TokenType}")
        };
    }

    public override void Write(Utf8JsonWriter writer, Segmentation value, JsonSerializerOptions options)
    {
        switch (value)
        {
            case PolygonSegmentation polygon:
                JsonSerializer.Serialize(writer, polygon.Polygons, options);
                break;
            case RleSegmentation rle:
                JsonSerializer.Serialize(writer, rle, options);
                break;
            default:
                throw new JsonException($"未知的Segmentation类型: {value.GetType().FullName}");
        }
    }
}

实现说明

  • 逻辑完全对齐COCO官方规范:iscrowd=0时segmentation固定为多边形数组,iscrowd=1时固定为RLE对象,类型判断不会出现匹配错误。
  • 不需要额外添加类型鉴别字段,序列化后的结果和官方COCO格式完全一致,不会出现兼容性问题。
  • 字段全程使用强类型声明,完全规避object类型带来的类型安全问题,后续扩展业务逻辑时可直接在基类添加抽象方法,减少冗余的类型判断代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 03:12:34