XLua 學習之路(二)之C#訪問Lua
這裡指的是C#主動發起對Lua資料結構的訪問。從Lua支援的資料型別來講,C#獲取Lua元素主要分為:基本資料型別(number,bool,string),複雜的資料型別(table),函式(function)。
本次測試的待獲取的Lua檔案CSharpCallLua.lua.txt內容t如下:
--用於測試獲取全域性基本資料型別 a = 100;--全域性變數 isDead = false str = "leander" --用於測試獲取全域性函式型別 function addTest() print("addTest") end --用於測試獲取全域性函式帶引數型別 function add(a,b) print(a+b) end --用於測試獲取全域性函式帶多個返回值型別 function addReturnMulti(a,b) return a+b,a,b end --用於測試獲取全域性table資料型別 preson={ name = "leander",2,"test",3.3, age = 24, --self引數,代表當前table物件 sum = function(self,a,b) print("a+b="+(a+b)) end } --使用“:”定義 --預設帶一個self引數,代表當前呼叫物件 --[ --用於測試獲取全域性table外部定義函式(不顯式第一個引數)型別 function preson:sum(a,b) print(a+b) end --] --使用“.”定義 --[ --用於測試獲取全域性table外部定義函式(顯式第一個引數)型別 function preson.sum(self,a,b) print(a+b) end --]
###一、獲取全域性基本資料型別
首先,還是建立XLua的虛擬機器。然後,再通過LuaEnv.Global.Get<型別>(“name”)方法進行獲取即可;示例程式碼如下:
LuaEnv env = new LuaEnv();//建立Lua虛擬機器 //讀取CSharpCallLua.lua.txt檔案 env.DoString("require 'CSharpCallLua'"); //C#獲取lua的基本資料型別 int a = env.Global.Get<int>("a"); bool isDead = env.Global.Get<bool>("isDead"); string str = env.Global.Get<string>("str"); print(a); //100 print(isDead); //False print(str); //leander env.Dispose(); //釋放Lua虛擬機器
###二、獲取全域性table型別
獲取table型別,一共有四種方式:1.將table對映到普通class或struct 2.對映到介面(優先考慮)3.對映到Dictionary或List 4.通過XLua的LuaTable完成對映;下面將分別完成這四種的對映。
####1.對映到普通class或struct
這種方式下xLua會幫你new一個例項,並把對應的欄位賦值過去。table的屬性可以多於或者少於class的屬性。可以巢狀其它複雜型別。要注意的是,這個過程是值拷貝,如果class比較複雜代價會比較大。而且修改class的欄位值不會同步到table,反過來也不會。這個功能可以通過把型別加到GCOptimize生成降低開銷。實現方式如下:
首先,構建table對應的class。
//第一種對映方式
class Preson
{
//欄位名要與lua檔案table中保持一致
public string name;
public int age;
}
再通過LuaEnv.Global.Get<型別>(“name”)方法進行獲取即可;示例程式碼如下:
//要注意的是,這個過程是值拷貝,如果class比較複雜,代價會比較大。
//而且修改class的欄位值不會同步到table,反過來也不會。
Preson p = env.Global.Get<Preson>("preson");
print(p.name + ":" + p.age);//leander:24
p.name = "leander.com";
env.DoString("print(preson.name)");//leander 注意:此處並不是leander.com
注意:此方法,不能對映table中的函式,若要對映到table中的函式,則考慮第二種對映方式。
####2.對映到介面
這種方式依賴於生成程式碼(如果沒生成程式碼會拋InvalidCastException異常),程式碼生成器會生成這個interface的例項,如果get一個屬性,生成程式碼會get對應的table欄位,如果set屬性也會設定對應的欄位。甚至可以通過interface的方法訪問lua的函式。實現方式如下:
首先,構建table對應的interface。
//第二種對映方式
[CSharpCallLua] //如果不加這個屬性就會拋InvalidCastException異常
interface IPerson
{
//介面不能包含欄位,將其轉換成屬性
string name { get; set; }
int age { get; set; }
//函式名稱需要與lua檔案函式名一致
void sum(int a,int b);
}
再通過LuaEnv.Global.Get<型別>(“name”)方法進行獲取即可;示例程式碼如下:
//2.對映到介面(優先考慮)
//這個過程是引用拷貝,修改IPerson的屬性會同步到table
IPerson p = env.Global.Get<IPerson>("preson");
print(p.name); //leander
p.name = "leanderQT";
env.DoString("print(preson.name)");//leanderQT 注意:此時name的value被更新了
p.sum(12, 32); //44 相當於p.Sum(p,12,32);
注意:對映class和struct和對映到interface的區別在於:1.對映class和struct是值拷貝,而對映到interface為引用拷貝。2.對映到interface時,需要新增[CSharpCallLua]註解,用於XLua生成程式碼。
####3.對映到Dictionary或List
不想定義class或者interface的話,可以考慮用這個,前提table下key和value的型別都是一致的。
//3.對映到Dictionary 或 List
//List只能對映值,無法對映key-value形式 比如:name:leander age:24 函式等
List<object> list = env.Global.Get<List<object>>("preson");
foreach (object o in list)
{
print(o);
}//輸出 2 "test" 3.3
//Dictionary只能對映key-value形式,無法對映值,比如:數字,字串等
Dictionary<string, object> dict = env.Global.Get<Dictionary<string, object>>("preson");
foreach (string key in dict.Keys)
{
print(key + ":" + dict[key]);
}//輸出 name:leander age:24 sum:function:11
注意:List只能對映值,無法對映key-value形式;Dictionary只能對映key-value形式,無法對映值形式。
####4.通過XLua的LuaTable完成對映
這種方式好處是不需要生成程式碼,但也有一些問題,比如慢,比方式2要慢一個數量級,比如沒有型別檢查。
//4.通過XLua的LuaTable完成對映 只能獲取table中的key-value形式(包括函式)
//若table中包含其他非key-value形式,下面程式碼將會報InvalidCastException異常
//在測試這段程式碼時,需要將lua檔案的table裡面2,"test",3.3移除,因為這種屬於非key-value形式
LuaTable tab = env.Global.Get<LuaTable>("preson");
print(tab.Get<string>("name")); //leander
print(tab.Get<int>("age")); //24
print(tab.Length); //獲取table中非key-value形式的元素個數
foreach (string key in tab.GetKeys())
{
print(tab.Get<object>(key));
}//輸出 leander 24 0
此處的函式,被對映成0了,原因還在排查…
###三、獲取全域性函式
仍然是用Get方法,不同的是型別對映。獲取function,一共有兩種方式:1、對映到delegate 2.對映到LuaFunction。
####1.對映到delegate
這種是建議的方式,效能好很多,而且型別安全。缺點是要生成程式碼(如果沒生成程式碼會拋InvalidCastException異常)。示例程式碼如下:
首先,定義函式對應的委託型別。
[CSharpCallLua]
//無返回值時委託定義
delegate void Add(int a,int b);
[CSharpCallLua]
//多個返回值時委託定義 除去該方法第一個返回值時,使用out/ref關鍵字來接收
delegate int AddReturnMulti(int a, int b, out int resa,out int resb);
然後還是基於Get方法。
//訪問lua中的全域性函式 對映到delegate
//無參型別
Action addTest = env.Global.Get<Action>("addTest");
addTest(); //addTest
//在釋放該虛擬機器之前,要先釋放上述對映的全域性函式
addTest = null;
//帶參型別 1.通過自定義委託型別來實現對映
Add add_Params = env.Global.Get<Add>("add");
add_Params(1, 3);//4
add_Params = null;
//多個返回值
AddReturnMulti addReturnMulti = env.Global.Get<AddReturnMulti>("addReturnMulti");
int resa, resb;
int result = addReturnMulti(34, 39, out resa, out resb);
print(resa + "+" + resb + "=" + result);//34+39=73
addReturnMulti = null;
####2.對映到LuaFunction
LuaFunction上有個變參的Call函式,可以傳任意型別,任意個數的引數,返回值是object的陣列,對應於lua的多返回值。
LuaFunction func = env.Global.Get<LuaFunction>("addReturnMulti");
object[] os = func.Call(1,2);
foreach (object o in os)
{
print(o);
}//3 1 2
###四、小結
1、訪問lua全域性資料,特別是table以及function,代價比較大,建議儘量少做,比如在初始化時把要呼叫的lua function獲取一次(對映到delegate)後,儲存下來,後續直接呼叫該delegate即可。table也類似。
2、如果lua測的實現的部分都以delegate和interface的方式提供,使用方可以完全和xLua解耦:由一個專門的模組負責xlua的初始化以及delegate、interface的對映,然後把這些delegate和interface設定到要用到它們的地方。
相關推薦
XLua 學習之路(二)之C#訪問Lua
這裡指的是C#主動發起對Lua資料結構的訪問。從Lua支援的資料型別來講,C#獲取Lua元素主要分為:基本資料型別(number,bool,string),複雜的資料型別(table),函式(function)。 本次測試的待獲取的L
Android外掛化學習之路(二)之ClassLoader完全解析
Java程式碼都是寫在Class裡面的,程式執行在虛擬機器上時,虛擬機器需要把需要的Class載入進來才能建立例項物件並工作,而完成這一個載入工作的角色就是ClassLoader。 類載入器ClassLoader介紹 Android的Dalvik/ART虛擬
Java學習之路(二)流程控制語句
循環 cas 學習之路 將不 乘法表 length 跳出循環 spa int if、if…else…語句 if (true) { System.out.println("為真時執行");
python學習之路(二) -- 函數、JSON、終端樣式
blog ade def 數量 通過 等於 name tuple args 函數 函數構成 定義函數:使用def即可 def __getName(idCard): return user_info[idCard].Name 其中,__get
Python 學習之路(二)
在外 封裝 過程 數列 == 3.6 開頭 res form Python 學習之路(二) 以下所用的是Python 3.6 一、條件語句 簡單判斷 1 if 判斷條件: 2 執行語句…… 3 else: 4 執行語句…… 復雜判斷 1 if 判斷
Hadoop學習之路(二)Hadoop發展背景
chukwa 站點 avro azkaban das 可擴展性 對數 就是 pro Hadoop產生的背景 1. HADOOP最早起源於Nutch。Nutch的設計目標是構建一個大型的全網搜索引擎,包括網頁抓取、索引、查詢等功能,但隨著抓取網頁數量的增加,遇到了嚴重的可擴
C++再學習之路(二)
iter pointer lin clas 數組元素 對數 表達 自增 條件操作符 1. 移位操作符“ << ”和“ >> ”擁有中等優先級:其優先級比算術操作符低,但比關系操作符、賦值操作符和條件操作符優先級高 2. *iter++ 後自增操作
HBase學習之路 (二)HBase集群安裝
star java_home 服務 blog usr mirrors logs 技術 ron 前提 1、HBase 依賴於 HDFS 做底層的數據存儲 2、HBase 依賴於 MapReduce 做數據計算 3、HBase 依賴於 ZooKeeper 做服務協調 4
Hive學習之路 (二)Hive安裝
different 0.10 director lar blog cut cti mysql extend Hive的下載 下載地址http://mirrors.hust.edu.cn/apache/ 選擇合適的Hive版本進行下載,進到stable-2文件夾可以看到穩
Spark學習之路 (二)Spark2.3 HA集群的分布式安裝
serve html 元數據 不安裝 rec ive cut 再次 apps 一、下載Spark安裝包 1、從官網下載 http://spark.apache.org/downloads.html 2、從微軟的鏡像站下載 http://mirrors.hust.
學習之路(二)淺談:bash及其特性,命令歷史以及用戶管理及權限,shell的類型
bash 管理權限 過了一周了,進度似乎有點懈怠,不過過了周末重整旗鼓啦shell(外殼)GUI:Gnome,KDE,xfceCLI:sh,csh,ksh,bashbash(父進程)-----bash(子進程)他們相互獨立彼此不知命令歷史:historybash支持的引號:‘ ’命令替換(鍵盤~的按鍵
小強的Hadoop學習之路(二)
com TE 區別 截斷 用戶 分開 路徑問題 登陸用戶 學習 接著第一遍。中間間隔了大約半年的時間了,話不多說,直接進入主題。 這篇是主要是應用篇。目前的環境是4臺機器 ,環境 centos 7.2 CDH5.10.2 網上很多安裝教程,這邊就不說明了。 Hive+
XML學習之路(二)
req 方式 test 無符號 規範 內容 了解 實體 文本 DTD 一、什麽是DTD? DTD即Document Type Definition,文檔類型定義。 我們知道,XML的標簽可以自定義,不受任何約束。但有時侯,為了符合邏輯和業務需要,我們需要對XML文檔加以約束
Linux 學習之路(二):使用者及許可權詳解
作業: 1.ls 命令是否可以顯示某目錄的整體大小,即包括其內部的所有檔案的整體大小? 可以,使用ls -s xxx 2.通過幫助手冊,學習使用du命令: # du 估計檔案空間使用量 -s 分割資料夾,不包括子目錄大小 -h 以可讀格式展示
Tecnomatix Plant Simulation 14 學習之路(二)
本篇部落格主要介紹基礎遺傳演算法的實現,例子參考部落格一推薦的周金平老師教材第三章,這裡做簡單介紹 問題描述: 將n個裝置(M1,…Mn)放置到n個位置(A,B…)上,其中每個位置上能且僅能放置一臺裝置,已知n個裝置兩兩之間的物料搬運量大小W(i, j),以及
Kafka學習之路 (二)Kafka的架構
most 工具 路由 冪等 用戶 toc 目標 支持 mem 一、Kafka的集群架構 如上圖所示,一個典型的Kafka集群中包含若幹Producer(可以是web前端產生的Page View,或者是服務器日誌,系統CPU、Memory等),若幹broker(Kafka支持
Flume學習之路 (二)Flume的Source類型
bash 官方 tip size pipes lte using exc 正常 一、概述 官方文檔介紹:http://flume.apache.org/FlumeUserGuide.html#flume-sources 二、Flume Sources 描述 2.1 Avro
Weex學習之路(二)除錯篇
寫在前面:作為前端開發工作者,一款好的除錯工具必不可缺。你可能已經習慣了chorme提供的簡單好用的網頁除錯工具,但在weex中,除錯是一個巨坑!! Weex除錯踩坑之旅 在weex中,除錯是一件非常麻煩但事,好在weex官方文件中提供了一些方案 1. weex-toolkit命
PKI學習之路(二)-----------------------淺談socket
首先為什麼要用socket? 如果沒有socket,我們傳輸資料需要藉助TCP/IP協議,不僅需要三次握手,還要友好分手,每次傳輸都要經過複雜的連線,具體傳輸過程中,也會有一大堆的問題,什麼滑動視窗,什麼累計確認,分組快取,流量控制,,,聽著就頭皮發麻,而socket就是TCP/IP的實現
Netty學習之路(二)-非同步IO(NIO)程式設計
NIO到底是什麼簡稱?有人稱之為New I/O,原因為他相對於之前的I/O類庫來說是新增的。這是官方叫法。但是,由於之前老的I/O類庫是阻塞I/O,New I/O類庫的目標就是讓java支援非阻塞I/O,所以更多的人稱之為非阻塞I/O(Non-block I/O)。在開始進行NIO程式設計之