在C#中,实体类可以通过System.Text.Json或Newtonsoft.Json库等方式直接序列化为json字符串,key为字段(属性)名,value为值。
上面的方式虽然实现简单,但是有个缺陷,就是转化后的json给外人展示时不够直观,key是英文的,有的value甚至是一些代号、枚举之类的,总之就是难以阅读和提取到有效的信息,不能应付老板的离谱需求。
下面介绍一种可行性的方案,在json序列化的时候,将key转为字段中文名,value转为对应的中文描述,通过继承重写Newtonsoft.Json库(演示版本为13.0.3)中的JsonConverter类来实现。
1、写一个NameAttribute特性
FieldName:属性的中文名称,用于替换属性名(也就是原本的key);IsEnum:是否类枚举,用于处理int类型的代号。
/// <summary>
/// 属性中文名称的特性
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class NameAttribute : Attribute
{
public string FieldName { get; }
public bool IsEnum { get; }
public NameAttribute(string fieldName)
{
FieldName = fieldName;
}
public NameAttribute(string fieldName, bool isEnum)
{
FieldName = fieldName;
IsEnum = isEnum;
}
}
2、写一个KeyValue类,用来存原本value中的代号和对应的中文描述
/// <summary>
/// 键值模型
/// </summary>
public class KeyValue
{
public KeyValue(int key, string value)
{
Key = key;
Value = value;
}
/// <summary>
/// 键
/// </summary>
public int Key { get; set; }
/// <summary>
/// 值
/// </summary>
public string Value { get; set; }
}
3、写一个泛型类JsonToChineseConverter<T>,继承JsonConverter
写一个有参构造函数,用来传递参数。这里传的是Dictionary类型,字典的key为实体类的属性名称;字典的value为List<KeyValue>类型,用来存类枚举。
/// <summary>
/// 传入value为list类型的中文名称
/// </summary>
private Dictionary<string, List<KeyValue>> KvDic { get; set; } = new Dictionary<string, List<KeyValue>>();
public JsonToChineseConverter(Dictionary<string, List<KeyValue>> kvDic)
{
KvDic = kvDic;
}
继承JsonConverter的类需要重写一下3个方法:
a、重写CanConvert方法,用来校验类型
/// <summary>
/// 校验能够转化的类型
/// </summary>
/// <param name="objectType"></param>
/// <returns></returns>
public override bool CanConvert(Type objectType)
{
return objectType == typeof(T);
}
b、重写ReadJson方法,用来读取json字符串,反序列化的时候使用,这里不做实现
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException("Deserialize is not implemented.");
}
c、重写WriteJson方法,用来读取实体类字段和值,序列化的时候使用
通过反射的方式取实体类的字段、值和Name特性;忽略value为null、空的字符串、DateTime.MinValue、DateTime.MaxValue的字段,可自行调整。
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JObject jsonObject = new JObject();
PropertyInfo[] properties = value.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
//value为null、空的字符串、DateTime.MinValue、DateTime.MaxValue时,则忽略
object fieldValue = property.GetValue(value);
if (fieldValue == null || string.IsNullOrWhiteSpace(fieldValue.ToString()) || (property.PropertyType == typeof(DateTime) && (Convert.ToDateTime(fieldValue) == DateTime.MinValue || Convert.ToDateTime(fieldValue) == DateTime.MaxValue)))
{
continue;
}
//key默认字段名,有Name注解时则取中文名
string fieldName = property.Name;
//取Name注解
NameAttribute nameAttribute = property.GetCustomAttribute<NameAttribute>();
if (nameAttribute != null)
{
fieldName = nameAttribute.FieldName;
}
//字段为List<int>类型时,将int转为对应的对应的中文
if (property.PropertyType == typeof(List<int>))
{
var kv = KvDic[property.Name];
if (kv != null && kv.Count > 0)
{
var fv = fieldValue as List<int>;
fieldValue = kv.Where(d => fv.Contains(d.Key)).Select(d => d.Value).ToList();
}
}
else if (property.PropertyType == typeof(int) && nameAttribute != null && nameAttribute.IsEnum == true)
{
var kv = KvDic[property.Name];
if (kv != null && kv.Count > 0)
{
var fv = fieldValue as int?;
fieldValue = (kv.FirstOrDefault(d => d.Key == fv.Value)?.Value) ?? fieldValue;
}
}
else if (property.PropertyType == typeof(bool))
{
if (Convert.ToBoolean(fieldValue) == true)
{
fieldValue = "是";
}
else
{
fieldValue = "否";
}
}
jsonObject[fieldName] = JToken.FromObject(fieldValue, serializer);
}
jsonObject.WriteTo(writer);
}
完整的类代码如下:
/// <summary>
/// 用Newtonsoft.Json序列化JSON时的扩展,将key、value转为对应的中文名称
/// </summary>
/// <typeparam name="T"></typeparam>
public class JsonToChineseConverter<T> : JsonConverter
{
/// <summary>
/// 传入value为list类型的中文名称
/// </summary>
private Dictionary<string, List<KeyValue>> KvDic { get; set; } = new Dictionary<string, List<KeyValue>>();
public JsonToChineseConverter(Dictionary<string, List<KeyValue>> kvDic)
{
KvDic = kvDic;
}
/// <summary>
/// 校验能够转化的类型
/// </summary>
/// <param name="objectType"></param>
/// <returns></returns>
public override bool CanConvert(Type objectType)
{
return objectType == typeof(T);
}
/// <summary>
/// 读取JSON,不实现
/// </summary>
/// <param name="reader"></param>
/// <param name="objectType"></param>
/// <param name="existingValue"></param>
/// <param name="serializer"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException("Deserialize is not implemented.");
}
/// <summary>
/// 写入JSON
/// </summary>
/// <param name="writer"></param>
/// <param name="value"></param>
/// <param name="serializer"></param>
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
JObject jsonObject = new JObject();
PropertyInfo[] properties = value.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
//value为null、空的字符串、DateTime.MinValue、DateTime.MaxValue时,则忽略
object fieldValue = property.GetValue(value);
if (fieldValue == null || string.IsNullOrWhiteSpace(fieldValue.ToString()) || (property.PropertyType == typeof(DateTime) && (Convert.ToDateTime(fieldValue) == DateTime.MinValue || Convert.ToDateTime(fieldValue) == DateTime.MaxValue)))
{
continue;
}
//key默认字段名,有Name注解时则取中文名
string fieldName = property.Name;
//取Name注解
NameAttribute nameAttribute = property.GetCustomAttribute<NameAttribute>();
if (nameAttribute != null)
{
fieldName = nameAttribute.FieldName;
}
//字段为List<int>类型时,将int转为对应的对应的中文
if (property.PropertyType == typeof(List<int>))
{
var kv = KvDic[property.Name];
if (kv != null && kv.Count > 0)
{
var fv = fieldValue as List<int>;
fieldValue = kv.Where(d => fv.Contains(d.Key)).Select(d => d.Value).ToList();
}
}
else if (property.PropertyType == typeof(int) && nameAttribute != null && nameAttribute.IsEnum == true)
{
var kv = KvDic[property.Name];
if (kv != null && kv.Count > 0)
{
var fv = fieldValue as int?;
fieldValue = (kv.FirstOrDefault(d => d.Key == fv.Value)?.Value) ?? fieldValue;
}
}
else if (property.PropertyType == typeof(bool))
{
if (Convert.ToBoolean(fieldValue) == true)
{
fieldValue = "是";
}
else
{
fieldValue = "否";
}
}
jsonObject[fieldName] = JToken.FromObject(fieldValue, serializer);
}
jsonObject.WriteTo(writer);
}
}
4、单元测试
下面用TestModel类进行测试
public class TestModel()
{
[Name("ID")]
public int Id { get; set; }
[Name("姓名")]
public string Name { get; set; }
[Name("性别", true)]
public int Sex { get; set; }
[Name("年龄")]
public int Arg { get; set; }
[Name("老师")]
public List<int> Teacher { get; set; }
[Name("是否毕业")]
public bool IsGraduation { get; set; }
public int? Field1 { get; set; } = null;
public string Field2 { get; set; } = " ";
public DateTime Field3 { get; set; } = DateTime.MinValue;
public DateTime Field4 { get; set; } = DateTime.MaxValue;
public bool Field5 { get; set; } = false;
}
测试方法如下:
[TestMethod]
public void WriteJsonTest1()
{
TestModel model = new TestModel()
{
Id = 1,
Name = "张楚岚",
Sex = 1,
Arg = 22,
Teacher = new List<int>() { 1, 2 },
IsGraduation = true
};
Dictionary<string, List<KeyValue>> kvDic = new Dictionary<string, List<KeyValue>>();
kvDic.Add("Sex", new List<KeyValue>() { new KeyValue(0, "未知"), new KeyValue(1, "男"), new KeyValue(2, "女") });
kvDic.Add("Teacher", new List<KeyValue>() { new KeyValue(1, "张怀义"), new KeyValue(2, "张之维") });
string joStr = JsonConvert.SerializeObject(model, new JsonSerializerSettings
{
Converters = new List<JsonConverter>() { new JsonToChineseConverter<TestModel>(kvDic) },
});
}
输出结果: