UH4L14——序列化库

本章代码关键字

1
JsonMapper.RegisterILRuntimeCLRRedirection()    //ILRuntime修改的LitJson特有的方法,热更工程如果要使用则必须调用该方法注册,传入appDomain

ILRuntime中使用序列化库

序列化库在我们开发当中经常会用到,比如之前我们学过的 LitJson、Protobuf
但是这些库都是存在于主工程中的,那么当使用他们序列化反序列化热更工程中的对象时,他们是不能识别的
所以在ILRuntime中使用序列化库,需要对其进行修改

注意:改写序列化库时,不能通过Activator​来创建实例

ILRuntime在使用第三方库时,为了能够正常的对热更工程中声明的类对象进行使用
我们往往需要对其进行修改,修改第三方库对于大家来说可能有一定难度
所以首先去ILRuntime的群和社区中去找找有没有别人做好的,如果没有再尝试自己修改

使用改好的LitJson库

假设在热更工程内要对下面的类序列化和反序列化

1
2
3
4
5
6
7
8
9
10
11
12
using System.Collections.Generic;

namespace HotFix_Project
{
class Lesson18_Test
{
public int testI;
public string testStr;
public List<int> listTest;
public Dictionary<string, int> dictTest;
}
}
  1. 初始化时注册 LitJson.JsonMapper.RegisterILRuntimeCLRRedirection(appDomain)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    private unsafe void InitILRuntime()
    {
    //注册委托和委托转换器...
    //注册跨域继承类
    appDomain.RegisterCrossBindingAdaptor(new ILRuntimeAdapter.Lesson11_TestAdapter());
    appDomain.RegisterCrossBindingAdaptor(new CoroutineAdapter());
    appDomain.RegisterCrossBindingAdaptor(new IAsyncStateMachineClassInheritanceAdaptor());
    //初始化LitJson相关内容
    LitJson.JsonMapper.RegisterILRuntimeCLRRedirection(appDomain);
    //注册值类型
    appDomain.RegisterValueTypeBinder(typeof(Vector3), new Vector3Binder());
    appDomain.RegisterValueTypeBinder(typeof(Vector2), new Vector2Binder());
    appDomain.RegisterValueTypeBinder(typeof(Quaternion), new QuaternionBinder());


    //CLR重定向内容,必须要写到CLR绑定之前!!!
    System.Type debugType = typeof(Debug);
    MethodInfo methodInfo = debugType.GetMethod("Log", new System.Type[] { typeof(object) });
    appDomain.RegisterCLRMethodRedirection(methodInfo, MyLog);

    //注册 CLR绑定相关信息
    ILRuntime.Runtime.Generated.CLRBindings.Initialize(appDomain);
    //初始化ILRuntime相关信息(目前只需要告诉ILRuntime主线程的线程ID,主要目的是能够在Unity的Profiler剖析器窗口中分析问题)
    appDomain.UnityMainThreadID = Thread.CurrentThread.ManagedThreadId;
    }
  2. 正常使用LitJson进行序列化反序列化

    • 序列化:JsonMapper.ToJson(对象)​

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      public class ILRuntimeMain
      {
      public static void Main()
      {
      Lesson18_Test test = new Lesson18_Test();
      test.testI = 99;
      test.testStr = "唐老狮";
      test.listTest = new List<int>() { 1, 2, 3, 4, 5 };
      test.dictTest = new Dictionary<string, int>() { { "1", 2 }, { "2", 88 }, { "3", 77 } };
      //序列化Json字符串
      string str = JsonMapper.ToJson(test);
      Debug.Log(str);
      }
      }
    • 反序列化:JsonMapper.ToObject<类型>​

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      public class ILRuntimeMain
      {
      public static void Main()
      {
      Lesson18_Test test = new Lesson18_Test();
      test.testI = 99;
      test.testStr = "唐老狮";
      test.listTest = new List<int>() { 1, 2, 3, 4, 5 };
      test.dictTest = new Dictionary<string, int>() { { "1", 2 }, { "2", 88 }, { "3", 77 } };
      //序列化Json字符串
      string str = JsonMapper.ToJson(test);
      Debug.Log(str);
      //反序列化Json字符串
      Lesson18_Test test2 = JsonMapper.ToObject<Lesson18_Test>(str);
      Debug.Log(test2.testI);
      Debug.Log(test2.testStr);
      }
      }

输出:image

如何自己改相关库

  1. 正确创建热更类型的实例(利用之前反射相关的创建方式)
  2. 获取泛型容器类的真实热更类型
  3. 序列化子对象
  4. 重定向泛型方法

去查看LitJson修改后的源码来分析加了哪些内容,JsonMapper​内部对泛型方法的重定向如下:

关于这里的逻辑,建议配合UH4L21——重定向的书写规则观看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public unsafe static void RegisterILRuntimeCLRRedirection(ILRuntime.Runtime.Enviorment.AppDomain appdomain)
{
foreach(var i in typeof(JsonMapper).GetMethods())
{
if(i.Name == "ToObject" && i.IsGenericMethodDefinition)
{
var param = i.GetParameters();
if(param[0].ParameterType == typeof(string))
{
appdomain.RegisterCLRMethodRedirection(i, JsonToObject);
}
else if(param[0].ParameterType == typeof(JsonReader))
{
appdomain.RegisterCLRMethodRedirection(i, JsonToObject2);
}
else if (param[0].ParameterType == typeof(TextReader))
{
appdomain.RegisterCLRMethodRedirection(i, JsonToObject3);
}
}
}
}

public unsafe static StackObject* JsonToObject(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
{
ILRuntime.Runtime.Enviorment.AppDomain __domain = intp.AppDomain;
StackObject* ptr_of_this_method;
StackObject* __ret = ILIntepreter.Minus(esp, 1);
ptr_of_this_method = ILIntepreter.Minus(esp, 1);
System.String json = (System.String)typeof(System.String).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, mStack));
intp.Free(ptr_of_this_method);
var type = method.GenericArguments[0].ReflectionType;
var result_of_this_method = ReadValue(type, new JsonReader(json));

return ILIntepreter.PushObject(__ret, mStack, result_of_this_method);
}

public unsafe static StackObject* JsonToObject2(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
{
ILRuntime.Runtime.Enviorment.AppDomain __domain = intp.AppDomain;
StackObject* ptr_of_this_method;
StackObject* __ret = ILIntepreter.Minus(esp, 1);
ptr_of_this_method = ILIntepreter.Minus(esp, 1);
JsonReader json = (JsonReader)typeof(JsonReader).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, mStack));
intp.Free(ptr_of_this_method);
var type = method.GenericArguments[0].ReflectionType;
var result_of_this_method = ReadValue(type, json);

return ILIntepreter.PushObject(__ret, mStack, result_of_this_method);
}

public unsafe static StackObject* JsonToObject3(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
{
ILRuntime.Runtime.Enviorment.AppDomain __domain = intp.AppDomain;
StackObject* ptr_of_this_method;
StackObject* __ret = ILIntepreter.Minus(esp, 1);
ptr_of_this_method = ILIntepreter.Minus(esp, 1);
TextReader json = (TextReader)typeof(TextReader).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, mStack));
intp.Free(ptr_of_this_method);
var type = method.GenericArguments[0].ReflectionType;
var result_of_this_method = ReadValue(type, new JsonReader(json));

return ILIntepreter.PushObject(__ret, mStack, result_of_this_method);
}