C#自定义Label控件JSON序列化仅保留自定义属性问题
嘿,这个问题我太熟了!当你继承WinForms的Label控件做自定义控件时,序列化时总会带出基类一大堆没用的属性,要只保留自己加的X、Y、H、W,有几个实用的方案,我给你拆解清楚:
方案1:用Newtonsoft.Json(Json.NET)的特性精准控制
如果你项目里用的是Json.NET(这是很多.NET项目的标配),可以通过特性直接指定哪些属性要序列化:
首先在你的自定义Label类上标记[JsonObject(MemberSerialization.OptIn)],意思是“只序列化我明确标记的属性”,然后给每个自定义属性加上[JsonProperty]:
using Newtonsoft.Json; using System.Windows.Forms; [JsonObject(MemberSerialization.OptIn)] public class CustomLabel : Label { [JsonProperty] public int X { get; set; } [JsonProperty] public int Y { get; set; } [JsonProperty] public int H { get; set; } [JsonProperty] public int W { get; set; } // 你的其他自定义逻辑... }
之后序列化的时候直接用JsonConvert.SerializeObject(customLabel),出来的JSON就只会包含X、Y、H、W这四个属性,基类的那些比如Text、Font、BackColor之类的都会被自动过滤掉。
方案2:用System.Text.Json的两种方式(.NET Core/.NET 5+)
如果你的项目用的是微软官方的System.Text.Json,有两种简单的做法:
方式A:匿名类型快速序列化
如果你的自定义属性不多,直接创建一个包含目标属性的匿名类型再序列化,简单粗暴又高效:
using System.Text.Json; var myCustomLabel = new CustomLabel { X = 10, Y = 20, H = 30, W = 40 }; var json = JsonSerializer.Serialize(new { myCustomLabel.X, myCustomLabel.Y, myCustomLabel.H, myCustomLabel.W });
方式B:自定义转换器(适合属性多或需要重复使用的场景)
如果以后可能添加更多自定义属性,或者需要统一处理序列化逻辑,可以写一个自定义的Json转换器:
using System.Text.Json; using System.Text.Json.Serialization; public class CustomLabelConverter : JsonConverter<CustomLabel> { // 反序列化逻辑(如果需要还原对象的话) public override CustomLabel Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var label = new CustomLabel(); using (var doc = JsonDocument.ParseValue(ref reader)) { label.X = doc.RootElement.GetProperty("X").GetInt32(); label.Y = doc.RootElement.GetProperty("Y").GetInt32(); label.H = doc.RootElement.GetProperty("H").GetInt32(); label.W = doc.RootElement.GetProperty("W").GetInt32(); } return label; } // 序列化逻辑:只写入我们关心的属性 public override void Write(Utf8JsonWriter writer, CustomLabel value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WriteNumber("X", value.X); writer.WriteNumber("Y", value.Y); writer.WriteNumber("H", value.H); writer.WriteNumber("W", value.W); writer.WriteEndObject(); } }
使用的时候把转换器加到序列化配置里:
var options = new JsonSerializerOptions(); options.Converters.Add(new CustomLabelConverter()); var json = JsonSerializer.Serialize(myCustomLabel, options);
方案3:创建DTO(数据传输对象)映射
如果不想依赖序列化框架的特性,或者需要在序列化前做一些属性转换、校验,最稳妥的方式是创建一个和自定义属性对应的DTO类:
// 定义DTO,只包含你要序列化的属性 public class CustomLabelDto { public int X { get; set; } public int Y { get; set; } public int H { get; set; } public int W { get; set; } } // 使用时把CustomLabel的属性复制到DTO里 var myCustomLabel = new CustomLabel { X = 10, Y = 20, H = 30, W = 40 }; var dto = new CustomLabelDto { X = myCustomLabel.X, Y = myCustomLabel.Y, H = myCustomLabel.H, W = myCustomLabel.W }; // 序列化DTO即可 var json = JsonSerializer.Serialize(dto); // 或者用JsonConvert.SerializeObject(dto)
这个方法的好处是解耦了控件类和序列化逻辑,就算以后控件类改了,只要调整DTO的映射就行,非常灵活。
内容的提问来源于stack exchange,提问作者DanialDP




