代码之家  ›  专栏  ›  技术社区  ›  TheRoadrunner

newtonsoft jsonconverter-将属性重命名为其他属性的值

  •  1
  • TheRoadrunner  · 技术社区  · 7 年前

    我有这门课:

    public class ValueInteger
    {
        [JsonIgnore]
        public string ValueName { get; set; }
    
        public int Value { get; set; }
    
        [JsonProperty("timestamp")]
        public UInt64 TimeStamp { get; set; }
    
    }
    

    举一个例子:

    var valueInt = new ValueInteger 
        { 
            ValueName = "mycounter",
            Value = 7,
            TimeStamp = 1010101010
        }
    

    它应该序列化为:

    { mycounter: 7, timestamp = 1010101010 }
    

    如果可以将Value属性声明为

        [JsonRedirect(titlePropertyName: nameof(ValueName))]
        public int Value { get; set; }
    

    我可能需要实现我自己的契约分解器,并研究这篇文章: https://stackoverflow.com/a/47872645/304820 但这取决于IvalueProvider,而Afaik没有用于重命名的InamProvider。

    通常,重命名是按类而不是按实例进行的。

    1 回复  |  直到 7 年前
        1
  •  1
  •   Anders Carstensen    7 年前

    我的方法是编写自己的转换器。转换器只是以与普通转换器相同的方式进行序列化,但是每当它遇到属性上的特殊属性时,它应该在输出中重命名该属性。

    因此,对C对象进行序列化如下:

    1. 首先将C对象转换为JSON对象(即jtokens结构)。
    2. 运行C对象中的属性,找到需要重命名的属性…
    3. 对于这些属性中的每一个,确定它们的当前名称和新名称。
    4. 对JSON对象执行重命名。
    5. 最后将JSON对象序列化为字符串。

    我已经做了一个简单的实现。用法如下:

    class Program
    {
        static void Main(string[] args)
        {
            var valueInt = new ValueInteger
            {
                ValueName = "mycounter",
                Value = 7,
                TimeStamp = 1010101010
            };
    
            var settings = new JsonSerializerSettings { Converters = new JsonConverter[] { new DynamicNameConverter() } };
            var result = JsonConvert.SerializeObject(valueInt, settings);
            Console.WriteLine(result);
            Console.Read();
        }
    }
    
    
    public class ValueInteger
    {
        [JsonIgnore]
        public string ValueName { get; set; }
    
        [JsonDynamicName(nameof(ValueName))]
        public int Value { get; set; }
    
        [JsonProperty("timestamp")]
        public UInt64 TimeStamp { get; set; }
    }
    

    帮助程序类:

    class DynamicNameConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            // Only use this converter for classes that contain properties with an JsonDynamicNameAttribute.
            return objectType.IsClass && objectType.GetProperties().Any(prop => prop.CustomAttributes.Any(attr => attr.AttributeType == typeof(JsonDynamicNameAttribute)));
        }
    
        public override bool CanRead => false;
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            // We do not support deserialization.
            throw new NotImplementedException();
        }
    
        public override bool CanWrite => true;
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var token = JToken.FromObject(value);
            if (token.Type != JTokenType.Object)
            {
                // We should never reach this point because CanConvert() only allows objects with JsonPropertyDynamicNameAttribute to pass through.
                throw new Exception("Token to be serialized was unexpectedly not an object.");
            }
    
            JObject o = (JObject)token;
            var propertiesWithDynamicNameAttribute = value.GetType().GetProperties().Where(
                prop => prop.CustomAttributes.Any(attr => attr.AttributeType == typeof(JsonDynamicNameAttribute))
            );
    
            foreach (var property in propertiesWithDynamicNameAttribute)
            {
                var dynamicAttributeData = property.CustomAttributes.FirstOrDefault(attr => attr.AttributeType == typeof(JsonDynamicNameAttribute));
    
                // Determine what we should rename the property from and to.
                var currentName = property.Name;
                var propertyNameContainingNewName = (string)dynamicAttributeData.ConstructorArguments[0].Value;
                var newName = (string)value.GetType().GetProperty(propertyNameContainingNewName).GetValue(value);
    
                // Perform the renaming in the JSON object.
                var currentJsonPropertyValue = o[currentName];
                var newJsonProperty = new JProperty(newName, currentJsonPropertyValue);
                currentJsonPropertyValue.Parent.Replace(newJsonProperty);
            }
    
            token.WriteTo(writer);
        }
    }
    
    [AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
    class JsonDynamicNameAttribute : Attribute
    {
        public string ObjectPropertyName { get; }
        public JsonDynamicNameAttribute(string objectPropertyName)
        {
            ObjectPropertyName = objectPropertyName;
        }
    }
    

    请注意,可能会进行大量的错误处理 DynamicNameConverter 但我把它省去了,这样更容易阅读和理解。

    推荐文章