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



我有这个类:

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。

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

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

因此,序列化一个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中可以放入许多错误处理,但为了便于阅读和理解,我省略了它。

最新更新