L#指令碼語言,直接把DLL當指令碼執行(圖解說明)

瘋光無線發表於2015-01-11

L#是什麼:Run DLL as a Script.

A Pure C# IL Runner,直接解析執行IL的指令碼引擎。

從原理上講是模擬執行了CLR的工作,從表現上講就是把DLL作為資源直接載入執行。

是不是很多同學夢寐以求的熱更DLL能熱更,但不是你想的那個熱更。

直接以反射符號的方式載入DLLDLL的解釋執行還是由CLR完成的。還會涉及JIT引擎。
但是L#"模擬"CLR的工作。不使用反射載入符號,不使用JIT
IOSUnity)、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();

    }

執行結果

相關文章