NewtonSoft JsonConverter-将属性重命名为其他属性的值

时间:2018-07-21 07:15:03

标签: c# json serialization

我上了这个课:

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; }

我可能必须实现自己的ContractResolver,并研究了这篇文章:https://stackoverflow.com/a/47872645/304820 但是它取决于IValueProvider和AFAIK,没有用于重命名的INameProvider。

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

1 个答案:

答案 0 :(得分:1)

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

因此,序列化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中可能会包含很多错误处理,但是为了便于阅读和理解,我省略了它。