Newtonsoft.Json笔记 -JsonConverter
通常的序列化与反序列化中的json结构与c#中的类模型结构是相对应的,我们是否可以在序列化一个对象时候,让我们json的数据结构能按照自己的意愿,而不必与该对象的数据结构一样呢?,比如说,一个对象,只有一个名为"ID"的int类型的属性,值为1,如果序列化该对象,则能得到json:{"ID":1},但我现在希望得到的json的"ID"值是bool类型:{"ID":true}。要满足能够进行自定义序列化与反序列化的要求,我们可以运用json.net中的转换器JsonConverter。
JsonConverter
Newtonsoft.Json命名空间下的一个抽象类JsonConverter,我们先来看下这个抽象类的成员:
public abstract class JsonConverter
{
public abstract void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer);
public abstract object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer);
public abstract bool CanConvert(Type objectType);
public virtual bool CanRead => true;
public virtual bool CanWrite => true;
}
JSON.NET提供的JsonConverter
XmlNodeConverter、UnixDateTimeConverter、ExpandoObjectConverter、EntityKeyMemberConverter、DiscriminatedUnionConverter、DataTableConverter、DataSetConverter、BsonObjectIdConverter、BinaryConverter
VersionConverter:序列化System.Version类型时使用
IsoDateTimeConverter:日期格式
public class student
{
//通过属性格式
[JsonConverter(typeof(DateFormat))]
public DateTime BirthDay { get; set; }
[JsonConverter(typeof(DateTimeFormat))]
public DateTime CreateTime { get; set; }
}
public class DateFormat:IsoDateTimeConverter
{
public DateFormat()
{
base.DateTimeFormat = "yyyy-MM-dd";
}
}
public class DateTimeFormat:IsoDateTimeConverter
{
public DateTimeFormat()
{
base.DateTimeFormat = "yyyy-MM-dd HH:mm:ss";
}
}
RegexConverter:序列化Regex类型时使用
private void WriteJson(JsonWriter writer, Regex regex, JsonSerializer serializer)
{
DefaultContractResolver? resolver = serializer.ContractResolver as DefaultContractResolver;
writer.WriteStartObject();
writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(PatternName) : PatternName);
writer.WriteValue(regex.ToString());
writer.WritePropertyName((resolver != null) ? resolver.GetResolvedPropertyName(OptionsName) : OptionsName);
serializer.Serialize(writer, regex.Options);
writer.WriteEndObject();
}
KeyValuePairConverter:序列化KeyValuePair<,>类型时使用
JavaScriptDateTimeConverter:将时间类型的属性序列化为Javascript类型的时间格式
JavaScriptDateTimeConverter converter = new JavaScriptDateTimeConverter();
DateTime d = new DateTime(2000, 12, 15, 22, 11, 3, 55, DateTimeKind.Utc);
string result = JsonConvert.SerializeObject(d, converter);
Assert.AreEqual("new Date(976918263055)", result);
StringEnumConverter:用于序列化时显示枚举的名称,而不是枚举值
如何使用
定义一个转换器类MyConverter,这个类要实现这三个抽象方法CanConvert()、ReadJson()、WriteJson()
在序列化Model对象的时候,程序会走到MyConverter下已经实现的WriteJson()方法,反序列化会走到ReadJson()方法,而CanConvert方法是用于判断是否需要自定义序列化或者反序列化的,它的参数objectType对应着特性JsonConverter所标记类的对应Type类型。
三种方式设置Converter
- 在我们要自定义序列化的类或属性上标记
[JsonConverter(typeof(MyConverter))]
- 在序列化、反序列化时使用
string j = JsonConvert.SerializeObject(s, new JsonSerializerSettings
{
Converters = { new JavaScriptDateTimeConverter() }
});
- 全局设置
services.AddNewtonsoft(.....);
案例1
先来个简单的例子:
[JsonConverter(typeof(MyConverter))]
public class Model
{
public int ID { get; set; }
}
public class MyConverter : JsonConverter
{
//是否开启自定义反序列化,默认值为true时,反序列化时会走ReadJson方法,值为false时,不走ReadJson方法,而是默认的反序列化
public override bool CanRead => true;
//是否开启自定义序列化,默认值为true时,序列化时会走WriteJson方法,值为false时,不走WriteJson方法,而是默认的序列化
public override bool CanWrite => true;
public override bool CanConvert(Type objectType)
{
return typeof(Model) == objectType;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var model = new Model();
//获取JObject对象,该对象对应着我们要反序列化的json
var jobj = serializer.Deserialize<JObject>(reader);
//从JObject对象中获取键位ID的值
var id = jobj.Value<bool>("ID");
//根据id值判断,进行赋值操作
if (id)
{
model.ID = 1;
}
else
{
model.ID = 0;
}
//最终返回的model对象就是json反序列化所得到的Model对象
//主要,这里的model对象不一定非得是Model类型,ReadJson方法与WriteJson方法是一样的,可以自由操作反序列生成的对象或者序列化生成的json
return model;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
//new一个JObject对象,JObject可以像操作对象来操作json
var jobj = new JObject();
//value参数实际上是你要序列化的Model对象,所以此处直接强转
var model = value as Model;
if (model.ID != 1)
{
//如果ID值为1,添加一个键位"ID",值为false
jobj.Add("ID",false);
}
else
{
jobj.Add("ID", true);
}
//通过ToString()方法把JObject对象转换成json
var jsonstr = jobj.ToString();
//调用该方法,把json放进去,最终序列化Model对象的json就是jsonstr,由此,我们就能自定义的序列化对象了
writer.WriteValue(jsonstr);
}
}
class Program
{
static void Main(string[] args)
{
var model = new Model();
model.ID = 1;
var json = JsonConvert.SerializeObject(model);//由于ID值为1,得到json为{"ID":ture}
var newModel = JsonConvert.DeserializeObject<Model>(json);//序列化得到的newModel对象ID值为1
}
}
案例2
以上例子是在类上添加JsonconvertAttribute,下面在属性上添加JsonConvertAttribute:
public class BoolConvert : JsonConverter
{
private string[] arrBString { get; set; }
public BoolConvert()
{
arrBString = "是,否".Split(',');
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="BooleanString">将bool值转换成的字符串值</param>
public BoolConvert(string BooleanString)
{
if (string.IsNullOrEmpty(BooleanString))
{
throw new ArgumentNullException();
}
arrBString = BooleanString.Split(',');
if (arrBString.Length != 2)
{
throw new ArgumentException("BooleanString格式不符合规定");
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
bool isNullable = IsNullableType(objectType);
Type t = isNullable ? Nullable.GetUnderlyingType(objectType) : objectType;
if (reader.TokenType == JsonToken.Null)
{
if (!IsNullableType(objectType))
{
throw new Exception(string.Format("不能转换null value to {0}.", objectType));
}
return null;
}
try
{
if (reader.TokenType == JsonToken.String)
{
string boolText = reader.Value.ToString();
if (boolText.Equals(arrBString[0], StringComparison.OrdinalIgnoreCase))
{
return true;
}
else if (boolText.Equals(arrBString[1], StringComparison.OrdinalIgnoreCase))
{
return false;
}
}
if (reader.TokenType == JsonToken.Integer)
{
//数值
return Convert.ToInt32(reader.Value) == 1;
}
}
catch (Exception ex)
{
throw new Exception(string.Format("Error converting value {0} to type '{1}'", reader.Value, objectType));
}
throw new Exception(string.Format("Unexpected token {0} when parsing enum", reader.TokenType));
}
/// <summary>
/// 判断是否为Bool类型
/// </summary>
/// <param name="objectType">类型</param>
/// <returns>为bool类型则可以进行转换</returns>
public override bool CanConvert(Type objectType)
{
return true;
}
public bool IsNullableType(Type t)
{
if (t == null)
{
throw new ArgumentNullException("t");
}
return (t.BaseType.FullName=="System.ValueType" && t.GetGenericTypeDefinition() == typeof(Nullable<>));
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value == null)
{
writer.WriteNull();
return;
}
bool bValue = (bool)value;
if (bValue)
{
writer.WriteValue(arrBString[0]);
}
else
{
writer.WriteValue(arrBString[1]);
}
}
}
public class Person
{
[JsonConverter(typeof(BoolConvert))]
public bool IsMarry { get; set; }
}
参考:
https://www.cnblogs.com/yijiayi/p/10051284.html
https://blog.csdn.net/MDZZ666/article/details/92838531
https://blog.csdn.net/stwuyiyu/article/details/51190548