C#对象序列化如何实现动态属性名?求最佳反序列化方案
实现动态属性名的序列化与反序列化方案
当然可以实现你想要的序列化需求!下面我会基于C#生态里最常用的两个JSON处理库(Newtonsoft.Json/Json.NET和System.Text.Json),分别讲解序列化的实现方式,以及最佳的反序列化方案。
一、序列化实现
1. 快速实现:匿名对象/字典映射
如果只是简单场景,不需要复用逻辑,直接用匿名对象或者字典来转换是最快捷的:
Newtonsoft.Json 版本
var home = new Home { Id = 2, propertyName = "administration", Text = "text1" }; var json = JsonConvert.SerializeObject(new { home.Id, [home.propertyName] = home.Text });
System.Text.Json 版本
var home = new Home { Id = 2, propertyName = "administration", Text = "text1" }; var jsonDict = new Dictionary<string, object> { { "Id", home.Id }, { home.propertyName, home.Text } }; var json = JsonSerializer.Serialize(jsonDict);
2. 通用方案:自定义Json转换器
如果需要在多个场景复用这个序列化逻辑,或者处理更复杂的对象结构,自定义Json转换器是更优雅的选择:
Newtonsoft.Json 自定义转换器
public class HomeConverter : JsonConverter<Home> { public override void WriteJson(JsonWriter writer, Home value, JsonSerializer serializer) { var jsonObj = new JObject(); jsonObj.Add("Id", value.Id); jsonObj.Add(value.propertyName, value.Text); jsonObj.WriteTo(writer); } // 反序列化逻辑会在后面讲 public override Home ReadJson(JsonReader reader, Type objectType, Home existingValue, bool hasExistingValue, JsonSerializer serializer) { var jObj = JObject.Load(reader); var home = new Home(); home.Id = jObj.GetValue("Id").Value<int>(); // 提取除Id外的动态属性 var dynamicProp = jObj.Properties().First(p => p.Name != "Id"); home.propertyName = dynamicProp.Name; home.Text = dynamicProp.Value.Value<string>(); return home; } }
使用转换器序列化:
var json = JsonConvert.SerializeObject(home, new HomeConverter());
System.Text.Json 自定义转换器
public class HomeJsonConverter : JsonConverter<Home> { public override void Write(Utf8JsonWriter writer, Home value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WriteNumber("Id", value.Id); writer.WriteString(value.propertyName, value.Text); writer.WriteEndObject(); } // 反序列化逻辑会在后面讲 public override Home Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using var doc = JsonDocument.ParseValue(ref reader); var root = doc.RootElement; var home = new Home(); home.Id = root.GetProperty("Id").GetInt32(); // 遍历找到动态属性 foreach (var prop in root.EnumerateObject()) { if (prop.Name != "Id") { home.propertyName = prop.Name; home.Text = prop.Value.GetString(); break; } } return home; } }
使用转换器序列化:
var options = new JsonSerializerOptions { Converters = { new HomeJsonConverter() } }; var json = JsonSerializer.Serialize(home, options);
二、最佳反序列化方式
反序列化的核心是识别出JSON中除Id之外的那个动态属性,把它的名称赋值给propertyName,值赋值给Text。这里推荐自定义Json转换器作为最佳方案,原因如下:
- 逻辑统一:同一个转换器可以同时处理序列化和反序列化,避免代码冗余
- 类型安全:相比手动解析字典,转换器能更可靠地处理类型转换,减少出错概率
- 扩展性强:如果后续类结构有变化,只需要修改转换器逻辑即可
当然,如果是非常简单的场景,也可以先反序列化成字典再手动映射:
Newtonsoft.Json 字典映射方式
var dict = JsonConvert.DeserializeObject<Dictionary<string, object>>(json); var home = new Home { Id = (int)dict["Id"], propertyName = dict.Keys.First(k => k != "Id"), Text = (string)dict[dict.Keys.First(k => k != "Id")] };
System.Text.Json 字典映射方式
var dict = JsonSerializer.Deserialize<Dictionary<string, object>>(json); var home = new Home { Id = Convert.ToInt32(dict["Id"]), propertyName = dict.Keys.First(k => k != "Id"), Text = dict[dict.Keys.First(k => k != "Id")] as string };
但这种方式在对象结构复杂或有多个动态属性时,容易出现空引用或类型转换错误,所以还是优先选择自定义转换器。
内容的提问来源于stack exchange,提问作者Alex Seitz
相关产品推荐
相关产品推荐

