介紹
ContractResolver能做什么:
為屬性添加一些序列化設置
自定義屬性名
有選擇的序列化屬性
CamelCasePropertyNamesContractResolver
Newtonsoft提供了CamelCasePropertyNamesContractResolver,繼承自ContractResolver,用於將屬性名轉成駝峰命名格式
//設置序列化時key為駝峰樣式
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
案例
為屬性添加一些序列化設置
//為屬性添加JsonConverter
public class PropertyResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var jsonProperty = base.CreateProperty(member, memberSerialization);
if (jsonProperty.PropertyType == typeof(DateTime))
{
jsonProperty.Converter = new DateTimeZoneConverter();
jsonProperty.ItemConverter = new DateTimeZoneConverter();
//var objType = jsonProperty.DeclaringType;//所在類Type
//jsonProperty.UnderlyingName;//屬性名
//jsonProperty.PropertyName = "aaa";//修改序列化后的屬性名
//var attributes = jsonProperty.AttributeProvider.GetAttributes(true);//獲取屬性上所有Attribute
//jsonProperty.PropertyType = typeof(string);
}
return jsonProperty;
}
}
自定義屬性名
需求:序列化時需要將屬性名以下划線分隔並小寫的格式顯示,如DogName序列化為dog_name
繼承DefaultContractResolver,重寫ResolvePropertyName方法
public class UnderlineSplitContractResolver : DefaultContractResolver
{
protected override string ResolvePropertyName(string propertyName)
{
return CamelCaseToUnderlineSplit(propertyName);
}
private string CamelCaseToUnderlineSplit(string name)
{
StringBuilder builder = new StringBuilder();
for (int i = 0; i < name.Length; i++)
{
var ch = name[i];
if (char.IsUpper(ch) && i > 0)
{
var prev = name[i - 1];
if (prev != '_')
{
if (char.IsUpper(prev))
{
if (i < name.Length - 1)
{
var next = name[i + 1];
if (char.IsLower(next))
{
builder.Append('_');
}
}
}
else
{
builder.Append('_');
}
}
}
builder.Append(char.ToLower(ch));
}
return builder.ToString();
}
}
public class Person
{
public string Name { get; set; }
public string DogName { get; set; }
[JsonProperty("cat_name_1")]
public string CatName { get; set; }
}
static void Main(string[] args)
{
JsonSerializerSettings settings = new JsonSerializerSettings
{
ContractResolver = new UnderlineSplitContractResolver()
};
Person p1 = new Person
{
Name = "fan",
DogName = "ahuang",
CatName = "nainiu"
};
var json = JsonConvert.SerializeObject(p1, settings);
Console.WriteLine(json);//輸出:{"name":"fan","dog_name":"ahuang","cat_name_1":"nainiu"}
Console.ReadKey();
}
控制屬性是否序列化
根據某些場景,可能A場景輸出A,B,C三個屬性,B場景輸出E,F屬性。雖然實際中不一定存在這種需求,但是json.net依然可以支持該特性。
繼承默認的DefaultContractResolver類,傳入需要輸出的屬性,retain表示props是需要保留的字段還是要排除的字段
public class LimitPropsContractResolver : DefaultContractResolver
{
string[] props = null;
bool retain;
/// <summary>
/// 構造函數
/// </summary>
/// <param name="props">傳入的屬性數組</param>
/// <param name="retain">true:表示props是需要保留的字段 false:表示props是要排除的字段</param>
public LimitPropsContractResolver(string[] props, bool retain=true)
{
//指定要序列化屬性的清單
this.props = props;
this.retain = retain;
}
protected override IList<JsonProperty> CreateProperties(Type type,
MemberSerialization memberSerialization)
{
IList<JsonProperty> list =
base.CreateProperties(type, memberSerialization);
//只保留清單有列出的屬性
return list.Where(p => {
if (retain)
{
return props.Contains(p.PropertyName);
}
else
{
return !props.Contains(p.PropertyName);
}
}).ToList();
}
public int Age { get; set; }
[JsonIgnore]
public bool IsMarry { get; set; }
public string Sex { get; set; }
string[] propNames = null;
if (p.Age > 10)
{
propNames = new string[] { "Age", "IsMarry" };
}
else
{
propNames = new string[] { "Age", "Sex" };
}
jsetting.ContractResolver = new LimitPropsContractResolver(propNames);
Console.WriteLine(JsonConvert.SerializeObject(p, Formatting.Indented, jsetting));