C#中集成Lua腳本


背景

  在很多時候我們代碼中的一些邏輯操作並不能夠硬編碼到代碼中,我們可能希望通過配置來完成這個操作,所以這個時候我們就需要有一些腳本語言能夠處理這些操作,在C#語言中比較常見的就是通過引入NLua這個動態庫來引入lua腳本語言從而達到靈活配置的目的,這篇文章主要是通過具體的實例來說明在C#中如何通過引入NLua並調用配置的腳本。

步驟

1 引入NLua.dll

  這個dll是一個很輕量級的庫,100kb左右,引用這個庫可以通過Nuget包管理器來引用,當前引用的版本是1.5.7.0,我們看看引用之后的添加了哪些DLL。

圖一 NLua包

 這個里面lua54.dll有x86和x64兩個類型的版本,這個在使用的時候需要注意因為我們生成設置選擇的是Any CPU所以這里會有兩個版本的dll,這里使用的時候需要注意。

2 具體用法

  下面通過一個控制台應用程序來看看這個腳本到底該怎么使用,這里包括直接創建表達式,注冊方法並使用lua調用C#函數以及直接導入C#的庫然后再調用里面內部的方法這三個方面進行描述。

  2.1 直接創建表達式

       我們來直接看控制台程序中的代碼

 class Program
    {
        static void Main(string[] args)
        {
            using (var state = new Lua())
            {
                //Evaluating simple expressions:
                //Lua can return multiple values, for this reason DoString return a array of objects
                var res0 = state.DoString("return 10 + 3*(5 + 2)")[0];
                Console.WriteLine($"Output result0:{res0}");

                //Passing raw values to the state:
                double val = 12.0;
                state["x"] = val; // Create a global value 'x' 
                var res1 = (double)state.DoString("return 10 + x*(5 + 2)")[0];
                Console.WriteLine($"Output result1:{res1}");

                //Retrieving global values:
                state.DoString("y = 10 + x*(5 + 2)");
                double y = (double)state["y"]; // Retrieve the value of y
                Console.WriteLine($"Y result:{y}");                
              
                Console.ReadKey();
            }
        }
}

 圖二 生成結果

  注意事項:

  首先來看這個注釋:Lua can return multiple values, for this reason DoString return a array of objects,就是直接調用DoString方法的時候返回的結果是一個object[]類型,所以這里需要取結果的時候要取用第一個 

 

圖三  DoString生成結果

  2.2 注冊Lua Function

  這里我們通過直接在DoString中定義好function,然后通過Call方法進行調用,我們再來看下面的示例及返回結果

    class Program
    {
        static void Main(string[] args)
        {
            using (var state = new Lua())
            {
                //Retrieving Lua functions:
                state.DoString(@"function ScriptFunc (val1, val2)
                                            if val1 > val2 then
                                                return val1 + 1
                                            else
                                                return val2 - 1
                                            end
                                        end
                                        ");
                var scriptFunc = state["ScriptFunc"] as LuaFunction;
                var funcRes = scriptFunc.Call(3, 5).First();
                Console.WriteLine($"Func result:{funcRes}");

                Console.ReadKey();
            }
        }
}

  同樣的我們也來看看最終執行的結果

圖四  Func.Call生成結果

  2.3 Lua調用C#函數

  下面的例子包含了幾種不同的參數類型及返回類型用來演示調用的完整過程。

using System;
using System.Linq;
using NLua;

namespace NLuaConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var state = new Lua())
            {
                ////---------------------------------------------------lua調用c#函數
                TestClass obj = new TestClass();

                // 注冊CLR對象方法到Lua,供Lua調用   typeof(TestClass).GetMethod("TestPrint")
                state.RegisterFunction("TestPrint", obj, obj.GetType().GetMethod("TestPrint"));

                // 注冊CLR對象方法到Lua,供Lua調用   typeof(TestClass).GetMethod("AnotherFunc")
                state.RegisterFunction("AnotherFunc", obj, obj.GetType().GetMethod("AnotherFunc"));

                // 注冊CLR靜態方法到Lua,供Lua調用
                state.RegisterFunction("TestStaticPrint", null, typeof(TestClass).GetMethod("TestStaticPrint"));

                state.DoString("TestPrint(10,20)");
                state.DoString("AnotherFunc('10','20')");
                state.DoString("TestStaticPrint()");

                Console.ReadKey();
            }
        }

        class TestClass
        {

            public int TestPrint(int num,int num2)
            {
                var result = num + num2;
                Console.WriteLine("Print result:" + result);
                return result;
            }

            public void AnotherFunc(string val1, string val2)
            {
                Console.WriteLine($"MyTest,Param1:{val1},Param2:{val2}");
            }

            public static void TestStaticPrint()
            {
                Console.WriteLine("TestStaticPrint");
            }
        }

    }
}

  同樣的我們來看整個測試的返回完整結果。

圖五 Lua調用C#函數返回結果

  2.4 通過Import導入命名空間引用C#函數

  這個是按照官方的例子進行模擬的,但是在調用的時候總是報錯,現貼出具體的示例供后面排查使用

class Program
    {
        static void Main(string[] args)
        {
            using (var state = new Lua())
            {
                state.LoadCLRPackage();
                state.DoString(@" import ('System.Web') ");
                state.DoString(@" client = WebClient() ");
                state.DoString(@"local res = client:DownloadString('http://nlua.org')");

                Console.ReadKey();
            }
        }
    }

  這個就是說通過調用C#程序集並引入命名空間,然后調用其內部的WebClient方法,這個在調試的時候一直都是報錯,這個暫時記錄供以后進行排查錯誤

圖六 Lua調用C#函數調用錯誤

3 總結

  這里有一些地方需要注意Lua對象是實現了IDispose接口的,所以我們在使用的時候需要注意使用using方式或者是使用后調用Dispose方法來對資源進行釋放。另外C#中引入Lua腳本的常見主要是適用於部分調用過程不適合硬編碼在代碼里而適合放在配置中,通過配置不同的Lua腳本從而對程序進行定制化操作,是對現有代碼一個很好的補充,另外對於調用C#中dll的方法出現的問題還在研究中,后面發現了再更新此過程。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM