Newton.Json中JsonConverter的使用

1、使用場景:json

有兩個類都繼承了同一個抽象類:ide

/// <summary>
/// 沙盒基類
/// </summary>
abstract class SandBoxGanmeBase
{
    /// <summary>
    /// 名稱
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// 版本
    /// </summary>
    public string Version { get; set; }

    /// <summary>
    /// 能夠駕駛
    /// </summary>
    public bool CanDrive { get { return true; } }
}

/// <summary>
/// GTA
/// </summary>
class GTA5 : SandBoxGanmeBase
{
    public bool HasHotCoffe { get; set; }
}

/// <summary>
/// Cyberpunk2077
/// </summary>
class Cyberpunk2077 : SandBoxGanmeBase
{
    public bool CanModifyDingDing { get { return true; } }
}

把信息保存入json:spa

string sJsonFile = AppDomain.CurrentDomain.BaseDirectory + "games.json";

IList<SandBoxGanmeBase> games = new List<SandBoxGanmeBase>();

games.Add(new GTA5()
{
    Name = "GTA5",
    Version = "1.53",
    HasHotCoffe = true
});

games.Add(new Cyberpunk2077()
{
    Name = "Cyberpunk2077",
    Version = "1.06"
});

string sJson = JsonConvert.SerializeObject(games, Formatting.Indented);

if (!File.Exists(sJsonFile))
    File.Create(sJsonFile).Close();

using (TextWriter chsTw = new StreamWriter(sJsonFile))
{
    chsTw.WriteLine(sJson);
chsTw.Flush();
}

games.json 內容:3d

 通常的,使用以下代碼讀取 games.json:code

 string sJsonFile = AppDomain.CurrentDomain.BaseDirectory + "games.json";

 string sJson = string.Empty;
 using (StreamReader sr = new StreamReader(sJsonFile))
     sJson = sr.ReadToEnd();

 IList<SandBoxGanmeBase> games = JsonConvert.DeserializeObject<IList<SandBoxGanmeBase>>(sJson);

會 catch ex 報錯:orm

由於,抽象類在 Newton.Json 反序列化時,沒法肯定繼承抽象類的實例,所以,咱們必需要告訴 Newton.Json:你須要使用哪一個類來進行反序列化,所以,JsonConverter 應運而生。對象

 

2、自定義 JsonConverterblog

class MyJsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(SandBoxGanmeBase).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        try
        {
            var jsonObject = JObject.Load(reader);
            object target = null;
            JToken gameName;
            if (jsonObject.TryGetValue("Name", out gameName))
            {
                switch (gameName.ToString())
                {
                    case "GTA5":
                        target = new GTA5();
                        break;
                    case "Cyberpunk2077":
                        target = new Cyberpunk2077();
                        break;
                }
            }
            serializer.Populate(jsonObject.CreateReader(), target);
            return target;
        }
        catch (Exception ex)
        {
            throw new Exception("解析異常:" + ex.Message);
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {

    }
}

修改讀取 games.json 代碼爲:繼承

string sJsonFile = AppDomain.CurrentDomain.BaseDirectory + "games.json";

string sJson = string.Empty;
using (StreamReader sr = new StreamReader(sJsonFile))
    sJson = sr.ReadToEnd();

IList<SandBoxGanmeBase> games = JsonConvert.DeserializeObject<IList<SandBoxGanmeBase>>(sJson, new MyJsonConverter());

反序列化正常:字符串

 

3、拓展----用特性方式使用 JsonConverter

一、反序列化

SandBoxGanmeBase 增長特性,修改成:

/// <summary>
/// 沙盒基類
/// </summary>
[JsonConverter(typeof(MyJsonConverter))]
abstract class SandBoxGanmeBase
{
    ...
}

讀取 games.json 方法還原爲:

...

IList<SandBoxGanmeBase> games = JsonConvert.DeserializeObject<IList<SandBoxGanmeBase>>(sJson);

二、序列化

僅爲 SandBoxGanmeBase 增長了特性,再進行序列化時,序列化的 Json 字符串爲空,修改 MyJsonConverter,增長 CanWrite 屬性:

class MyJsonConverter : JsonConverter
{
    ...

public
override bool CanWrite { get { return false; } } ...

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { } }

這樣,在序列化對象時,就使用 Newton.Json 默認的 WriteJson 而不是使用 MyJsonConvert 中重寫的 WriteJson。

 

這應該是2020年最後一篇博客記錄了,2021年,一如既往,不要在小問題上重複犯錯!

相關文章
相關標籤/搜索