如何在Json.NET中基于对象动态属性为属性名添加前缀?
动态属性前缀的Json.NET序列化实现方法
问题场景
需要序列化一个对象,要求根据对象中动态变化的Prefix属性,为其他属性名添加对应前缀。由于Prefix是运行时动态值,无法提前用JsonProperty特性指定。示例代码如下:
public class Example { [JsonIgnore] public string Prefix { get; set; } public string Name { get; set; } public string Value { get; set; } }
序列化代码:
var fooExample = new Example { Prefix = "foo_", Name = "TestName", Value = "TestValue" }; JsonConvert.SerializeObject(fooExample);
期望输出:
{ "foo_Name": "TestName", "foo_Value": "TestValue" }
尝试过重写ContractResolver的CreateProperty方法,但无法获取父对象实例来读取Prefix值,代码如下:
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { JsonProperty property = base.CreateProperty(member, memberSerialization); // 无法从这里获取父对象的Prefix值 string prefix = ""; property.PropertyName = prefix + property.PropertyName; return property; }
需要找到Json.NET的其他实现方式。
解决方案
方案1:自定义JsonConverter
自定义JsonConverter可直接在序列化过程中访问当前对象实例,从而获取动态的Prefix值,具体实现如下:
public class PrefixPropertyConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(Example); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var example = (Example)value; var prefix = example.Prefix ?? string.Empty; writer.WriteStartObject(); // 遍历所有非JsonIgnore标记的属性 var properties = typeof(Example).GetProperties() .Where(p => !Attribute.IsDefined(p, typeof(JsonIgnoreAttribute))); foreach (var prop in properties) { var propValue = prop.GetValue(example); writer.WritePropertyName(prefix + prop.Name); serializer.Serialize(writer, propValue); } writer.WriteEndObject(); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { // 如需反序列化,可在此实现对应逻辑,示例暂省略 throw new NotImplementedException(); } }
使用方式:
var settings = new JsonSerializerSettings { Converters = new List<JsonConverter> { new PrefixPropertyConverter() } }; var json = JsonConvert.SerializeObject(fooExample, settings);
方案2:改进ContractResolver结合序列化上下文
若希望复用ContractResolver的逻辑,可通过JsonSerializerSettings的Context属性传递当前对象的前缀,实现如下:
public class PrefixContractResolver : DefaultContractResolver { protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) { var property = base.CreateProperty(member, memberSerialization); if (property.DeclaringType == typeof(Example) && !property.Ignored) { // 从序列化上下文中获取前缀 var prefix = JsonSerializer.Current.Context.Context as string; if (!string.IsNullOrEmpty(prefix)) { property.PropertyName = prefix + property.PropertyName; } } return property; } }
使用时传递上下文:
var settings = new JsonSerializerSettings { ContractResolver = new PrefixContractResolver(), Context = new StreamingContext(StreamingContextStates.All, fooExample.Prefix) }; var json = JsonConvert.SerializeObject(fooExample, settings);
此方式需注意上下文传递的正确性,逻辑相对自定义Converter稍复杂。
内容的提问来源于stack exchange,提问作者PrometheusMMIV
相关产品推荐
相关产品推荐

