如何在C#中用System.Text.Json正确序列化带命名元组的List
嘿,这个问题我之前也碰到过!核心原因是System.Text.Json默认不认命名ValueTuple的自定义字段名——你虽然写了(string oid,string data,string desc),但在底层,ValueTuple的实际字段是Item1、Item2、Item3,oid、data、desc只是编译时的别名,序列化器根本识别不了这些别名,再加上默认配置可能忽略了未公开的字段,所以就输出空的{}了。
下面给你几个实用的解决办法,按需选就行:
方法1:改用普通数据类(最推荐)
最稳妥的方式是把ValueTuple换成一个简单的数据类,这样序列化器能直接识别字段/属性名,后续维护也更方便:
// 定义一个专门的资产项类 public class AssetItem { public string Oid { get; set; } public string Data { get; set; } public string Desc { get; set; } } // 把Asset类里的列表改成这个类型 public List<AssetItem> assetData { get; set; }
之后用你原来的序列化代码,就能正常输出带字段名的JSON了,完全不用额外配置。
方法2:给ValueTuple写自定义转换器
如果你不想改现有数据结构,可以写一个自定义JsonConverter来处理这个命名元组:
public class AssetTupleConverter : JsonConverter<(string oid, string data, string desc)> { // 反序列化逻辑(如果需要反序列化的话) public override (string oid, string data, string desc) Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using var doc = JsonDocument.ParseValue(ref reader); var root = doc.RootElement; return ( root.GetProperty("oid").GetString()!, root.GetProperty("data").GetString()!, root.GetProperty("desc").GetString()! ); } // 序列化时手动写入我们想要的字段名 public override void Write(Utf8JsonWriter writer, (string oid, string data, string desc) value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WriteString("oid", value.oid); writer.WriteString("data", value.data); writer.WriteString("desc", value.desc); writer.WriteEndObject(); } }
然后在序列化的时候注册这个转换器就行:
private static void Serialize(Asset asset, JsonSerializerOptions? options = null) { var opts = options ?? new JsonSerializerOptions() { WriteIndented = true, IgnoreNullValues = true, }; // 添加自定义转换器 opts.Converters.Add(new AssetTupleConverter()); var json = JsonSerializer.Serialize<Asset>(asset, opts); Console.WriteLine(json); }
方法3:切换到Newtonsoft.Json(Json.NET)
如果项目允许换JSON库,Newtonsoft.Json对命名ValueTuple的支持要友好得多,默认就能识别你定义的oid、data、desc别名:
先通过NuGet安装Newtonsoft.Json包,然后修改序列化代码:
private static void Serialize(Asset asset) { var json = JsonConvert.SerializeObject(asset, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); Console.WriteLine(json); }
这种方式完全不用改你的assetData列表类型,直接就能输出符合预期的JSON。
小提醒
看你提供的数据示例,有些Data字段是空的,比如第一条OID= 1.3.6.1.2.1.1.1.0对应的Data是空值,因为你设置了IgnoreNullValues = true,这些空值字段会被序列化器忽略,如果希望保留的话,可以把这个配置去掉。
另外要确保你的assetData里每个元组的desc成员都正确赋值了(比如对应示例里的BGP4-V2-MIB::bgpM2BaseNotifications),不然也会被忽略哦。
内容的提问来源于stack exchange,提问作者Vincent Vega

