修改LitJson支持继承多态:__type标记实现子类的反序列化

56 阅读1分钟

仓库

github.com/tsogzark/li…

思路

在LitJson进行Object反序列化的时候检查是否有__type字段,如果有,按照__type字段的string类型实例化。

使用示例

using System.Diagnostics;
using LitJson;

public class Program
{
    public static void Main(string[] args)
    {
        var snake = new Snake() { Length = 1f };
        var bird = new Bird() { FootCount = 1};
        var lion = new Lion() { Food = bird };
        List<Animal> animals = new List<Animal>() { snake, bird, lion };
        var jsonStr = JsonMapper.ToJson(animals);
        var outputAnimals = JsonMapper.ToObject<List<Animal>>(jsonStr);
        Debug.Assert(((Bird)outputAnimals[1]).FootCount == 1);
    }
    
    public class Animal 
    {
        public string __type;
        public bool Alive { get; set; }
        public Animal()
        {
            __type = GetType().AssemblyQualifiedName;
        }
    }
    
    public class Pet: Animal 
    {
        public string MasterName { get; set; }
    }
    
    public class Snake: Pet 
    {
        public float Length { get; set; }
    }
    
    public class Bird: Pet
    {
        public int FootCount { get; set; } 
    }
    
    public class Lion: Animal
    {
        public Animal Food { get; set; }
    }

}

核心代码

github.com/tsogzark/li…

    
    if (t_data.Properties.TryGetValue("__type", out var typeMeta) && check__type)
    {
        if (typeMeta.Type == typeof(string))
        {
            int count = 1;
            StringBuilder sb = new StringBuilder();
            sb.Append("{\"");
            while (count > 0)
            {
                var c = reader.ReadChar();
                if (c == -1)
                {
                    throw new JsonException("Cannot Find } For {");
                }

                if (c == '{')
                {
                    count++;
                }

                if (c == '}')
                {
                    count--;
                }

                sb.Append((char)c);
            }
            // 词法分析器目前期望string输入 跳过后重置为初始状态
            reader.SetLexerState(1); 
            // 移除ObjectPrime 期望下一个读入}
            reader.PopAutoMatonStack(); 
            reader.PushAutoMatonStack('}');
            // 原本是" 表示开始读属性 强制伪装成结束 故而会直接返回ObjectEnd
            reader.SetCurrentInput('}'); 
            // 对应于ReadValue函数的最后return instace 也即返回{} null 需要在List中移除多余的null
            var objStr = sb.ToString();
            var data = JsonMapper.ToObject(objStr);
            Type type = Type.GetType(data["__type"].ToString());
            if (type == null)
            {
                throw new JsonException("__type Field Is Not A Type Name");
            }
            else
            {
                return ReadValue(type, new JsonReader(objStr), false);
            }
        }
    }