当我调用JsonConvert.SerializeObject(...)函数时,有没有办法将我的任何自定义属性转换为某些东西?例如,我有一个班级:
class A
{
[UnitAttribute("---")]
public double? Ratio { get; set; }
}
序列化此类的任何实例时,有没有办法将UnitAttribute的值放入Json字符串?
我发现API中有一个IAttributeProvider接口。但似乎序列化函数并没有真正使用它。
答案 0 :(得分:0)
最简单的方法是创建一个JsonConverter
来添加属性文本(我假设它对应于单位,在这种情况下)并将转换器附加到属性:
class A
{
[JsonConverter(typeof(UnitConverter), new object [] { "mm" })]
public double? Ratio { get; set; }
}
public class UnitConverter : JsonConverter
{
public string Units { get; set; }
string UnitsPostfix { get { return string.IsNullOrEmpty(Units) ? string.Empty : " " + Units; } }
public UnitConverter(string units)
{
this.Units = units;
}
public override bool CanConvert(Type objectType)
{
throw new NotImplementedException(); // Not called when applied directly to a property.
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jvalue = JValue.Load(reader);
if (jvalue.Type == JTokenType.String)
{
var s = (string)jvalue;
if (s.EndsWith(Units))
jvalue = (JValue)s.Substring(0, s.LastIndexOf(Units)).Trim();
}
return jvalue.ToObject(objectType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var jvalue = JValue.FromObject(value);
if (jvalue.Type == JTokenType.Null)
jvalue.WriteTo(writer);
else
writer.WriteValue((string)jvalue + UnitsPostfix);
}
}
注意我可以将单位字符串直接传递给属性声明中的转换器构造函数。
如果您的代码库中有许多字段和属性UnitAttribute
,并希望自动将转换器应用于所有字段和属性,则可以创建从现有合同解析程序派生的自定义IContractResolver
as DefaultContractResolver
应用必要的转换器:
public class UnitContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (property.Converter == null && property.MemberConverter == null)
{
var attr = property.AttributeProvider.GetAttributes(typeof(UnitAttribute), true).Cast<UnitAttribute>().Where(a => !string.IsNullOrEmpty(a.Name)).FirstOrDefault();
if (attr != null)
{
property.Converter = property.MemberConverter = new UnitConverter(attr.Name);
}
}
return property;
}
}
您可以明确使用合约解析程序,如下所示:
var settings = new JsonSerializerSettings() { ContractResolver = new UnitContractResolver() };
var json = JsonConvert.SerializeObject(a, settings);
Debug.WriteLine(json);
var a11 = JsonConvert.DeserializeObject<A>(json, settings);
Debug.Assert(a.Ratio == a.Ratio);
或者在Json.net global settings中将其设置为自动使用。