文章目錄
客製 Json.NET 的 JsonConverter - 自動 Initial Value Type 屬性 (使用 JsonSerializer)
之前文章 客製 Json.NET 的 JsonConverter - 自動 Initial Value Type 屬性 介紹到可以在使用自訂 JsonConverter 在將物件轉為 json 前先進行初始化
後來同事在使用自訂 JsonConverter 時需採用另個 Json.Net 的語法 - JsonSerializer 遇到問題,事實上核心語法都相同,筆記一下用法,之後需要時就可以直接抄 XD
基本環境說明
自訂型別
public class userData<T> { public string TestName { get; set; } public Guid id { get; set; } public List<T> name { get; set; } public Dictionary<string,int> TestDic { get; set; } public IList<T> TestIList { get; set; } public IEnumerable<T> TestEnum { get; set; } public int[] Products{ get; set; } }
使用方式
以下使用 LINQPad 進行 demo
userData<string> user = new userData<string> {}; user.Dump(); JsonSerializer serializer = new JsonSerializer(); using (var sw = new StringWriter()) using (JsonWriter writer = new JsonTextWriter(sw)) { serializer.Serialize(writer,user); sw.ToString().Dump(); }
客製 JsonConverter
關於客製 JsonConverter 可以參考 Json.NET 的官方文件 Custom JsonConverter
public class InitialJsonConvert : JsonConverter
{
private readonly Type[] _types;
public InitialJsonConvert(params Type[] types)
{
_types = types;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// 取得傳入 class 型別
Type type = value.GetType();
// 取得傳 class 的 property 資訊
PropertyInfo[] propInfos = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
//propInfos.Dump();
// 針對所有 class 的 property 資訊操作
foreach (var element in propInfos)//.Where(p => p.GetIndexParameters().Length == 0))
{
//element.GetIndexParameters().Dump();
//element.GetIndexParameters().Length.Dump();
// 檢查傳入值是否為 null
if (element.GetValue(value) == null)
{
//取得 property 的型別
Type pt = element.PropertyType;
// string 是 value type 的特例,需要特別處理
if (pt == typeof(string))
{
// 使用 string.Empty 初始化 property
element.SetValue(value, string.Empty);
}
// array 也需要特別處理
else if (pt.IsArray)
{
//pt.Dump();
var arrayType=pt.GetElementType();
//arrayType.Dump();
element.SetValue(value,Array.CreateInstance(arrayType, 0) );
}
else if(pt.IsInterface && type.IsGenericType)
{
var Ttype=pt.GetGenericArguments()[0];
element.SetValue(value, Array.CreateInstance(Ttype,0));
}
else
{
// 使用 property 的型別來建立實體
//pt.Dump();
element.SetValue(value, Activator.CreateInstance(pt));
}
}
}
JToken t = JToken.FromObject(value);
if (t.Type != JTokenType.Object)
{
t.WriteTo(writer);
}
else
{
JObject o = (JObject)t;
IList<string> propertyNames = o.Properties().Select(p => p.Name).ToList();
o.AddFirst(new JProperty("Keys", new JArray(propertyNames)));
o.WriteTo(writer);
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
}
public override bool CanRead
{
get { return false; }
}
public override bool CanConvert(Type objectType)
{
return _types.Any(t => t == objectType);
}
}
如何使用
指定 JsonSerializer 格式
serializer.Formatting = Newtonsoft.Json.Formatting.Indented;
加入自訂 JsonConverter 至 JsonSerializer 中
serializer.Converters.Add(new InitialJsonConvert(user.GetType()));
實際效果
修改前與修改後程式碼
以下請使用 LINQPas 執行
//以下為修改前版本 //建立 demo 用 instance userData<string> user = new userData<string> { }; //輸出 data user.Dump(); //輸出 serialize 後的 json string JsonConvert.SerializeObject(user).Dump(); //以上為修改前版本 //以下為修改後版本 //建立 JsonSerializer instance JsonSerializer serializer = new JsonSerializer(); //指定 JsonSerializer 格式 serializer.Formatting = Newtonsoft.Json.Formatting.Indented; //加入自訂 JsonConvert serializer.Converters.Add(new InitialJsonConvert(user.GetType())); using (var sw = new StringWriter()) using (JsonWriter writer = new JsonTextWriter(sw)) { // serialize data serializer.Serialize(writer, user); // 輸出 data sw.ToString().Dump(); } // 輸出經過自訂 serialize 的 data (value type 已被初始化) user.Dump();
輸出結果
心得
主要程式是延用 客製 Json.NET 的 JsonConverter - 自動 Initial Value Type 屬性 並改用 JsonSerializer 來進行序列化的動作,適合用在 web request 直接將結果 data 序列化為 json 並透過 StreamWriter 輸出
參考資訊
文章作者 Yowko Tsai
上次更新 2021-11-02
授權合約
本部落格 (Yowko's Notes) 所有的文章內容(包含圖片),任何轉載行為,必須通知並獲本部落格作者 (Yowko Tsai) 的同意始得轉載,且轉載皆須註明出處與作者。
Yowko's Notes 由 Yowko Tsai 製作,以創用CC 姓名標示-非商業性-相同方式分享 3.0 台灣 授權條款 釋出。