L#是什么:Run DLL as a Script.
A Pure C# IL Runner,直接解析執行IL的腳本引擎。
從原理上講是模擬執行了CLR的工作,從表現上講就是把DLL作為資源直接加載執行。
是不是很多同學夢寐以求的熱更DLL?能熱更,但不是你想的那個熱更。
直接以反射符號的方式加載DLL,DLL的解釋執行還是由CLR完成的。還會涉及JIT引擎。
但是L#是"模擬"CLR的工作。不使用反射加載符號,不使用JIT
在IOS(Unity)、WP8這樣的平台,CLR就沒反射加載符號這樣的功能。IOS還關閉了JIT
L#不受這個制約
但是就帶來了其他制約:交互上的一些麻煩
主要記住這一條:L#加載的DLL中的代碼屬於腳本代碼,和系統代碼中的程序不能互相繼承
L#的語法是什么樣的:
L# 是直接運行dotnet 的DLL, 你可以用c# vb.net f# 等。只要能通過編譯。
與C#Light自己實現語法解釋問題不同,L#沒有語法解釋層面的bug,只會有執行層面的bug。
恰恰是C#Light在語法解釋器的維護上陷入泥潭以后,深刻反思,才有了L#這個創意。
關於代碼:
可以在http://svn.cltri.com 取得最新代碼
或者https://github.com/lightszero/lsharp
目前還處於Alpha階段,Bug是少不了的,這個階段僅建議動手能力比較強的同學試用。
發現BUG罵我是肯定要罵的,如果罵完之后,能夠在Github上推一個錯誤用例
將不甚感激。
下面介紹一下L#在Unity3D的使用辦法
一步一步是這樣,是魔鬼的步伐
L#ForUnity3D Hell#oworld環境建立圖解
1.創建新項目
2.Copy L#forU3D的類庫到DLL中
或者直接插入L#forU3D的源碼也可以,自選
3.創建一個代碼供L#模塊訪問)
剽竊了龐麥郎的歌詞,但我是不會道歉的
4.創建一個L#模塊
5.添加L#模塊的引用
因為我們剛才在plugins目錄下創建的代碼Interface.cs,希望L#模塊訪問他,就對應Assembly-Csharp-firstpass這個模塊
6.編寫L#模塊
可以看到L#模塊粗獷的調用了我們的程序
然后F7,你會得到L#模塊的dll文件
7.把模塊文件作為資源放進Unity3D
把模塊文件改名為
HotFixCode.Dll.bytes
HotFixCode.Pdb.bytes
pdb這個文件不是必須的,但是當腳本出異常,你需要查一下是哪個文件哪一行出錯的時候,沒有pdb是查不出來的。只能給你一個干巴巴的地址。
當然你熟悉IL的話,自己用別的工具,根據這個地址也是可以找到代碼位置的。
他在Unity里面應該被識別為兩個TextAsset
8.編寫測試程序Test001
新建場景並保存Test001,
新建Test001腳本直接掛接到攝像機上
編寫代碼如下:
using UnityEngine;
using System.Collections;
public class test001 : MonoBehaviour {
CLRSharp.CLRSharp_Environment env ;
// Use this for initialization
void Start () {
//創建CLRSharp環境
env=new CLRSharp.CLRSharp_Environment(new Logger());
}
// Update is called once per frame
void Update () {
}
public class Logger:CLRSharp.ICLRSharp_Logger//實現L#的LOG接口
{
public void Log (string str)
{
Debug.Log (str);
}
public void Log_Error (string str)
{
Debug.LogError (str);
}
public void Log_Warning (string str)
{
Debug.LogWarning (str);
}
}
}
9.執行HelloWorld
進入Unity,運行項目
這是唯一的結果,有一條Log L#被初始化了
L#HelloWorld 第二步,調用L#模塊圖解
繼續增加代碼
在Start函數后增加代碼
0.加載模塊
//加載L#模塊
TextAsset dll = Resources.Load("HoxFixCode.dll") as TextAsset;
TextAsset pdb = Resources.Load("HoxFixCode.pdb") as TextAsset;
System.IO.MemoryStream msDll = new System.IO.MemoryStream (dll.bytes);
System.IO.MemoryStream msPdb = new System.IO.MemoryStream (pdb.bytes);
//env.LoadModule (msDll, null);//不需要pdb的話,第二個參數傳null
env.LoadModule (msDll, msPdb);
1.創建線程上下文
2.取得准備調用的類型
3.調用靜態函數
4.調用成員函數
完整的start函數代碼
void Start () {
//創建CLRSharp環境
env=new CLRSharp.CLRSharp_Environment(new Logger());
//加載L#模塊
TextAsset dll = Resources.Load("HoxFixCode.dll") as TextAsset;
TextAsset pdb = Resources.Load("HoxFixCode.pdb") as TextAsset;
System.IO.MemoryStream msDll = new System.IO.MemoryStream (dll.bytes);
System.IO.MemoryStream msPdb = new System.IO.MemoryStream (pdb.bytes);
//env.LoadModule (msDll, null);//不需要pdb的話,第二個參數傳null
env.LoadModule (msDll, msPdb);
Debug.Log ("LoadModule HotFixCode.dll done.");
//step01建立一個線程上下文,用來模擬L#的線程模型,每個線程創建一個即可。
CLRSharp.ThreadContext context = new CLRSharp.ThreadContext (env);
Debug.Log ("Create ThreadContext for L#.");
//step02取得想要調用的L#類型
CLRSharp.ICLRType wantType = env.GetType ("HoxFixCode.TestClass",null);//用全名稱,包括命名空間
Debug.Log ("GetType:"+wantType.Name);
//和反射代碼中的Type.GetType相對應
//step03 靜態調用
//得到類型上的一個函數,第一個參數是函數名字,第二個參數是函數的參數表,這是一個沒有參數的函數
CLRSharp.IMethod method01 = wantType.GetMethod("Test1",CLRSharp.MethodParamList.MakeEmpty());
method01.Invoke (context, null, null);//第三個參數是object[] 參數表,這個例子不需要參數
//這是個靜態函數調用,對應到代碼他就是HotFixCode.TestClass.Test1();
//step04 成員調用
//第二個測試程序是一個成員變量,所以先要創建實例
CLRSharp.CLRSharp_Instance typeObj = new CLRSharp.CLRSharp_Instance (wantType as CLRSharp.ICLRType_Sharp);//創建實例
CLRSharp.IMethod methodctor = wantType.GetMethod(".ctor",CLRSharp.MethodParamList.MakeEmpty());//取得構造函數
methodctor.Invoke (context, typeObj, null);//執行構造函數
//這幾行的作用對應到代碼就約等於 HotFixCode.TestClass typeObj =new HotFixCode.TestClass();
CLRSharp.IMethod method02 = wantType.GetMethod("Test2",CLRSharp.MethodParamList.MakeEmpty());
method02.Invoke (context, typeObj, null);
//這兩行的作用就相當於 typeOBj.Test2();
}