亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

ToLua框架下C#與Lua代碼的互調(diào)操作

 更新時間:2020年11月17日 16:31:59   作者:達(dá)也醬  
這篇文章主要介紹了ToLua框架下C#與Lua代碼的互調(diào)操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

Lua是目前國內(nèi)使用最多的熱更語言,基于Lua的熱更框架也非常多,最近學(xué)習(xí)了一下ToLua的熱更框架,主要使用的問題在于C#和Lua之間的互調(diào),因此做一下學(xué)習(xí)記錄以備后查。

所謂“互調(diào)”,當(dāng)然要包括兩個方面,一是通過C#調(diào)用Lua代碼,二是通過Lua代碼調(diào)用C#腳本,第二點還包括注冊在C#腳本里的Unity物體。

1. ToLua的簡單實現(xiàn)原理

ToLua框架主要是通過靜態(tài)綁定來實現(xiàn)C#與Lua之間的交互的,基本原理是通過建立一個Lua虛擬機(jī)來映射C#腳本,然后再通過這個虛擬機(jī)來運(yùn)行Lua腳本,Lua腳本在運(yùn)行時可以通過虛擬機(jī)反過來調(diào)用C#腳本里注冊過的物體,這種方式的優(yōu)勢在于比起使用反射的uLua來說效率更高。

ToLua框架下可以將實現(xiàn)分成三大部分:普通的Unity+C#部分、ToLua虛擬機(jī)部分和Lua腳本部分,結(jié)構(gòu)見下圖:

ToLua結(jié)構(gòu)

目前國內(nèi)需要熱更的手游一般都將主要的邏輯框架和組件功能用C#實現(xiàn),而具體功能和調(diào)用放在Lua中,因為C#是不能被打包進(jìn)AssetBundle中的,所以無法通過AssetBundle對代碼進(jìn)行改動,但是Lua是即時編譯型語言,并且可以被打包進(jìn)入AssetBundle中,在需要修改簡單功能時,將Lua代碼通過AssetBundle進(jìn)行更新即可。

2. ToLua的下載的安裝

首先是下載地址:

ToLua

這是作者的github地址,進(jìn)入以后點擊下載Zip,完成后解壓到自己需要的目錄,再用Unity打開即可。

點擊下載zip即可

第一次打開工程時會提示是否需要自動生成注冊文件,新手可以選擇直接生成,若選擇了取消,也可以在編輯器菜單中手動注冊?!@是一個非常重要的操作,后文也會提到。

下面開始關(guān)于使用的正文。

3. ToLua的基本使用

前面有提到過ToLua的基本實現(xiàn)方式,這里可以再細(xì)化一點:創(chuàng)建虛擬機(jī)——綁定數(shù)據(jù)——調(diào)用Lua代碼,這套步驟在框架自帶的Example里也非常清晰。

首先脫離Example實現(xiàn)一下這三個步驟。

ToLua虛擬機(jī)的創(chuàng)建非常簡單,只需要new一個LuaState即可,我們建立一個C#腳本作為入口,引用LuaInterface命名空間,輸入以下代碼,將文件掛載到場景中的一個空物體上即可。

using LuaInterface;
using UnityEngine;
 
public class LuaScene : MonoBehaviour
{ 
 string luaString = @"
  print('這是一個使用DoString的Lua程序')
     ";
 string luaFile = "LuaStudy";
 LuaState state; 
 
 void Start()
 { 
 state = new LuaState();//建立Lua虛擬機(jī)
 state.Start();//啟動虛擬機(jī)
 
 //使用string調(diào)用Lua
 state.DoString(luaString);
 
 //使用文件調(diào)用Lua
 //手動添加一個lua文件搜索地址
 string sceneFile = Application.dataPath + "/LuaStudy";
 state.AddSearchPath(sceneFile);
 state.DoFile(luaFile);
 state.Require(luaFile);
 
 state.Dispose();//使用完畢回收虛擬機(jī)
 Debug.LogFormat("當(dāng)前虛擬機(jī)狀態(tài):{0}", null == state);//驗證虛擬機(jī)狀態(tài)
 } 
}

這里使用的Lua腳本也非常簡單

print('這是一個使用DoFile的Lua程序')

Lua掛載

ToLua直接調(diào)用Lua代碼的方式有兩種,一種是DoString,另一種是DoFile;此外還有一個Require方法,這個方法和前兩個方法不同的是,ToLua會將調(diào)用的Lua文件載入Lua棧中,而前兩者只是運(yùn)行一次,運(yùn)行之后保存在緩存中,雖然也可以后續(xù)調(diào)用,但是會。

在上述代碼中要注意,使用DoFile和Require方法時,要手動給目標(biāo)文件添加一個文件搜索位置。

運(yùn)行結(jié)果如下:

Lua運(yùn)行結(jié)果

最后,使用完畢記得清理虛擬機(jī),我使用null==state來進(jìn)行判斷,最后輸出“true”,說明調(diào)用LuaState.Dispose()后,虛擬機(jī)已經(jīng)被清理。

4. C#中調(diào)用Lua變量/函數(shù)

我們上面實現(xiàn)了C#調(diào)用Lua文件和string,其實對于ToLua而且,直接調(diào)用string和文件并沒有本質(zhì)區(qū)別,最后都會轉(zhuǎn)換成byte[]進(jìn)行載入。

接下來實現(xiàn)一下ToLua調(diào)用指定Lua變量和函數(shù),這里通過文件導(dǎo)入Lua代碼。

首先是我們的Lua代碼,這一段Lua代碼一共有一個普通變量、一個帶有函數(shù)的表,一個無參函數(shù),一個有參函數(shù),功能非常簡單,并且在這一段代碼中沒有調(diào)用。

num = 0
mytable={1,2,3,4}
mytable.tableFunc=function()
 print('調(diào)用TableFunc');
end
 
function Count()
 num=num+1
 print('計數(shù)器+1,當(dāng)前計數(shù)器為'..num)
 return num;
end
 
function InputValue( param)
 print('[lua中調(diào)用:]InputValue方法傳入?yún)?shù):'..tostring( param))
end

然后是C#代碼,還是一樣的套路,先創(chuàng)建虛擬機(jī),讀入Lua文件。下面依次說明普通變量、無參函數(shù)、有參函數(shù)和table的調(diào)用。

注意:如果帶有l(wèi)ocal標(biāo)識,那么C#中無法直接獲取

普通變量

普通變量的調(diào)用非常簡單,在載入文件后,通過LuaState[string]的形式就可以直接獲取到,也可以通過這個表達(dá)式來直接賦值。

無參函數(shù)

函數(shù)的調(diào)用有兩種方式,一是先緩存為LuaFunction類型后調(diào)用,二是直接能過Call方法調(diào)用。

有參函數(shù)

有參函數(shù)和無參函數(shù)調(diào)用的區(qū)別在于參數(shù)的傳入,在ToLua中重載了非常多的傳參函數(shù),與無參函數(shù)的調(diào)用方法相同,有參函數(shù)也有兩種調(diào)用方式,這里具體說明一下傳入?yún)?shù)的不同方式。

傳入?yún)⒑驼{(diào)用分離。

這種方式一般需要先將函數(shù)緩存為LuaFunction,然后使用BeginPcall方法標(biāo)記函數(shù),再使用Push或者PushArgs方法將參數(shù)傳入函數(shù),最后調(diào)用PCall,還可以調(diào)用EndPcall標(biāo)記結(jié)束。

 //對方法傳入?yún)?shù)
 LuaFunction valueFunc = state.GetFunction("InputValue");
 valueFunc.BeginPCall();
 valueFunc.Push("--push方法從C#中傳入?yún)?shù)--");
 valueFunc.PCall();

調(diào)用時直接傳入?yún)?shù)。

這是最符合一般操作邏輯的方式,但是查看實現(xiàn)代碼會發(fā)現(xiàn),事實上只是LuaFunction中封裝的一套實現(xiàn),其本質(zhì)和上一種是一樣的。

4.table

table是lua中的一個百寶箱,一切東西都可以往里裝,table里可以有普通的變量,還可以有table,也可以有方法。

在ToLua里對table的數(shù)據(jù)結(jié)構(gòu)進(jìn)行了解析,實現(xiàn)了非常多的方法,這里完全可以將table看一個LuaState來進(jìn)行操作,兩者沒有什么區(qū)別。

以下是完整的C#代碼,運(yùn)行結(jié)果后附。

using LuaInterface;
using UnityEngine; 
public class LuaAccess : MonoBehaviour
{
 string luaFile = "LuaAccess";
 LuaState state; 
 void Start()
 {
 state = new LuaState();
 state.Start();
 
 //使用文件調(diào)用Lua
 //手動添加一個lua文件搜索地址
 string sceneFile = Application.dataPath + "/LuaStudy";
 state.AddSearchPath(sceneFile);
 
 state.Require(luaFile);//載入文件
 
 //獲取Lua變量
 Debug.Log("獲取文件中變量:" + state["num"]);
 state["num"] = 10;
 Debug.Log("設(shè)置文件中變量為:" + state["num"]);
 
 //調(diào)用Lua方法
 LuaFunction luaFunc = state.GetFunction("Count");
 luaFunc.Call();
 Debug.Log("C#調(diào)用LuaFunc,函數(shù)返回值:" + state["num"]);
 
 Debug.Log("C#直接調(diào)用Count方法。");
 state.Call("Count", false); 
 
 //對方法傳入?yún)?shù)
 LuaFunction valueFunc = state.GetFunction("InputValue");
 valueFunc.BeginPCall();
 valueFunc.Push("--push方法從C#中傳入?yún)?shù)--");
 valueFunc.PCall();
 valueFunc.EndPCall();
 
 valueFunc.Call("--直接Call方法從C#傳入?yún)?shù)--"); 
 
 //獲取LuaTable
 LuaTable table = state.GetTable("mytable");
 table.Call("tableFunc");
 LuaFunction tableFunc = table.GetLuaFunction("tableFunc");
 Debug.Log("C#調(diào)用table中的func");
 tableFunc.Call();
 
 Debug.Log("獲取table中的num值:"+table["num"]);
 
 //通過下標(biāo)直接獲取
 for (int i = 0; i < table.Length; i++)
 {
  Debug.Log("獲取table的值:" + table[i]);
 } 
 
 //轉(zhuǎn)換成LuaDictTable
 LuaDictTable dicTable = table.ToDictTable();
 foreach (var item in dicTable)
 {
  Debug.LogFormat("遍歷table:{0}--{1}", item.Key, item.Value);
 } 
 
 state.Dispose();
 }
}

Lua訪問變量

5. Lua中調(diào)用C#方法/變量

之前在 @羅夏L的文章里看過一篇他關(guān)于lua調(diào)用C#的筆記,但總覺得少了點什么,所以在我自己記筆記的時候特別注意了一下具體的實現(xiàn)。

在@羅夏L的文章中,將一個C#對象作為參數(shù)傳入列表中,然后直接在Lua代碼里運(yùn)行對應(yīng)的方法名,其中少了幾個關(guān)鍵的步驟,如果只是進(jìn)行了這幾步,是實現(xiàn)不了在Lua里引用的。

首先還是從實現(xiàn)原理說起,在文章開始的第一節(jié)我提過ToLua的基本實現(xiàn)思路,并且將這套系統(tǒng)分成了三部分,在這三部分之中,ToLua作為一個橋梁實現(xiàn)了溝通Lua腳本和C#的功能,我們知道Lua的實質(zhì)是通過字節(jié)碼對C進(jìn)行了一套封裝,具有即時編譯的特點,從C#或者其他語言中來調(diào)用Lua都不算太困難,只需要提前約定特定方法名然后載入腳本即可,但C#是需要提前編譯的,怎么通過一段解釋器來調(diào)用C#中的對象就是主要的難點了,ToLua實現(xiàn)的就是這兩方面的功能。

從這方面來分析,我覺得大多數(shù)人會想到的最直接的實現(xiàn)思路大概都是通過反射來實現(xiàn),uLua也是通過反射來實現(xiàn)的,但是反射的效率非常低,雖然確實可以實現(xiàn),但問題還是非常明顯。

ToLua是通過方法名綁定的方式來實現(xiàn)這個映射的,首先構(gòu)造一個Lua虛擬機(jī),在虛擬機(jī)啟動后對所需的方法進(jìn)行綁定,在虛擬機(jī)運(yùn)行時可以在Lua中調(diào)用特定方法,虛擬機(jī)變相地實現(xiàn)了一個解釋器的功能,在Lua調(diào)用特定方法和對象時,虛擬機(jī)會在已綁定的方法中找到對應(yīng)的C#方法和對象進(jìn)行操作,并且ToLua已經(jīng)自動實現(xiàn)了一些綁定的方法 。

基本原理大概了解以后,我們就可以來看看它的具體實現(xiàn)了。

第一步還是建立虛擬機(jī)并且啟動,為了實現(xiàn)Lua對C#的調(diào)用,首先我們要調(diào)用一下綁定方法,于是我們的代碼變成了下面這樣??梢钥吹剑@里和之前的唯一區(qū)別是增加了LuaBinder.Bind(state)方法,這一個方法內(nèi)部其實是對許多定義好的方法的綁定,也就是上面說的綁定方法。

using LuaInterface;
using UnityEngine;
 
public class CSharpAccess : MonoBehaviour
{
 private string luaFile = "LuaCall";
 LuaState state;
 
 void Start()
 {
 state = new LuaState();
 state.Start();
 
 string sceneFile = Application.dataPath + "/LuaStudy";
 state.AddSearchPath(sceneFile);
 
 // 注冊方法調(diào)用
 LuaBinder.Bind(state);
 
 state.Require(luaFile);//載入文件
 }
}

然后我們加入一個變量和一個方法,我們要實現(xiàn)的是完成在Lua中對這個方法和變量的調(diào)用。

 public string AccessVar = "++這是初始值++";
 public void PrintArg(string arg)
 {
 Debug.Log("C#輸出變量值:" + arg);
 }

在有了目標(biāo)方法之后,我們要將這個變量和方法綁定進(jìn)入虛擬機(jī)中。

查看LuaState的實現(xiàn)代碼,可以發(fā)現(xiàn)綁定主要有RegFunction、RegVar和RegConstant三個方法,分別用于綁定函數(shù)/委托、變量和常量。在這里ToLua是通過一個委托來實現(xiàn)方法的映射,這個委托需要傳入一個luaState變量,類型是IntPtr,這個變量的實質(zhì)是一個句柄,在實際操作中,會將虛擬機(jī)作為變量傳入。

 public delegate int LuaCSFunction(IntPtr luaState); 
 public void RegFunction(string name, LuaCSFunction func);
 public void RegVar(string name, LuaCSFunction get, LuaCSFunction set);
 public void RegConstant(string name, double d);
 public void RegConstant(string name, bool flag);

總結(jié)一下幾個方法的特點:

這幾個方法都需要傳入一個string name,這個name就是之后在Lua中調(diào)用的變量或方法名。

RegConstant方法比較簡單,傳入一個name再傳入一個常量即可;

RegFunction和RegVar都是通過LuaCSFunction類型的委托實現(xiàn);

RegFunction需要一個LuaCSFunction委托,這個委托需要對原方法重新進(jìn)行一次實現(xiàn);

RegVar除了name之外,還需要兩個LuaCSFunction委托,可以理解為一個變量的get/set方法,如果只有g(shù)et或set,另一個留null即可。

接下來我們對AccessVar和PrintArg方法進(jìn)行一下LuaCSFunction形式的實現(xiàn)。

private int PrintCall(System.IntPtr L)
 {
 try
 {
  ToLua.CheckArgsCount(L, 2); //對參數(shù)進(jìn)行校驗
  CSharpAccess obj = (CSharpAccess)ToLua.CheckObject(L, 1, typeof(CSharpAccess));//獲取目標(biāo)對象并轉(zhuǎn)換格式
  string arg0 = ToLua.CheckString(L, 2);//獲取特定值
  obj.PrintArg(arg0);//調(diào)用對象方法
  return 1;
 }
 catch (System.Exception e)
 {
  return LuaDLL.toluaL_exception(L, e);
 }
 }
 
 private int GetAccesVar(System.IntPtr L)
 {
 object o = null;
 
 try
 {
  o = ToLua.ToObject(L, 1); //獲得變量實例
  CSharpAccess obj = (CSharpAccess)o; //轉(zhuǎn)換目標(biāo)格式
  string ret = obj.AccessVar; //獲取目標(biāo)值
  ToLua.Push(L, ret);//將目標(biāo)對象傳入虛擬機(jī)
  return 1;
 }
 catch (System.Exception e)
 {
  return LuaDLL.toluaL_exception(L, e, o, "attempt to index AccessVar on a nil value");
 }
 }
 
 private int SetAccesVar(System.IntPtr L)
 {
 object o = null;
 
 try
 {
  o = ToLua.ToObject(L, 1);//獲得變量實例
  CSharpAccess obj = (CSharpAccess)o;//轉(zhuǎn)換目標(biāo)格式
  obj.AccessVar = ToLua.ToString(L, 2);//將要修改的值進(jìn)行設(shè)定,注意這里如果是值類型可能會出現(xiàn)拆裝箱
  return 1;
 }
 catch (System.Exception e)
 {
  return LuaDLL.toluaL_exception(L, e, o, "attempt to index AccessVar on a nil value");
 }
 }

可以看到這三個方法的格式都是一致的,通用的步驟如下:

使用ToLua中的方法對L句柄進(jìn)行校驗,出現(xiàn)異常則拋出,本例中使用ToLua.CheckArgsCount方法;

獲得目標(biāo)類的實例,并轉(zhuǎn)換格式,具體轉(zhuǎn)換方法較多,可以根據(jù)需要在ToLua類中選擇,本例中使用了ToLua.CheckObject和ToLua.ToObject等方法;

調(diào)用對應(yīng)方法,不同的方法調(diào)用略有區(qū)別。

值得注意的是,在ToLua的ToObjectQuat、ToObjectVec2等獲取值類型的方法中,會出現(xiàn)拆裝箱的情況。

下一步將幾個方法注冊進(jìn)lua虛擬機(jī)。

注意這里有兩對方法,分別是BeginModule\EndModule和BeginClass\EndClass,BeginModule\EndModule用于綁定命名空間,可以逐層嵌套;而BeginClass\EndClass用于開啟具體的類型空間,具體的方法和變量綁定必須在這成對的方法之中,否則會導(dǎo)致ToLua崩潰(百試百靈,別問我怎么知道的)。

 private void Bind(LuaState L)
 {
 L.BeginModule(null);
 
 L.BeginClass(typeof(CSharpAccess), typeof(UnityEngine.MonoBehaviour));
 
 state.RegFunction("Debug", PrintCall);
 state.RegVar("AccessVar", GetAccesVar, SetAccesVar);
 
 L.EndClass();
 
 L.EndModule();
 }

最后是我們的Lua代碼,非常簡單,注意Debug和AccessVar調(diào)用的區(qū)別。

print('--進(jìn)入Lua調(diào)用--')
local go = UnityEngine.GameObject.Find("LuaScene")
local access=go:GetComponent("CSharpAccess")
access:Debug("Lua調(diào)用C#方法")
access.AccessVar="--這是修改值--"
print('--Lua調(diào)用結(jié)束--')

完整C#代碼

using LuaInterface;
using UnityEngine;
 
public class CSharpAccess : MonoBehaviour
{
 private string luaFile = "LuaCall";
 LuaState state;
 
 void Start()
 {
 state = new LuaState();
 state.Start(); 
 
 string sceneFile = Application.dataPath + "/LuaStudy";
 state.AddSearchPath(sceneFile);
 
 // 注冊方法調(diào)用
 LuaBinder.Bind(state);
 Bind(state); 
 
 Debug.Log("AccessVar初始值:" + AccessVar); 
 state.Require(luaFile);//載入文件
 Debug.Log("C#查看:" + AccessVar);
 
 state.Dispose();
 }
 
 private void Bind(LuaState L)
 {
 L.BeginModule(null);
 L.BeginClass(typeof(CSharpAccess), typeof(UnityEngine.MonoBehaviour));
 state.RegFunction("Debug", PrintCall);
 state.RegVar("AccessVar", GetAccesVar, SetAccesVar);
 L.EndClass();
 L.EndModule();
 }
 
 private int PrintCall(System.IntPtr L)
 {
 try
 {
  ToLua.CheckArgsCount(L, 2); //對參數(shù)進(jìn)行校驗
  CSharpAccess obj = (CSharpAccess)ToLua.CheckObject(L, 1, typeof(CSharpAccess));//獲取目標(biāo)對象并轉(zhuǎn)換格式
  string arg0 = ToLua.CheckString(L, 2);//獲取特定值
  obj.PrintArg(arg0);//調(diào)用對象方法
  return 1;
 }
 catch (System.Exception e)
 {
  return LuaDLL.toluaL_exception(L, e);
 }
 }
 
 public void PrintArg(string arg)
 {
 Debug.Log("C#輸出變量值:" + arg);
 }
 
 [System.NonSerialized]
 public string AccessVar = "++這是初始值++";
 private int GetAccesVar(System.IntPtr L)
 {
 object o = null;
 
 try
 {
  o = ToLua.ToObject(L, 1); //獲得變量實例
  CSharpAccess obj = (CSharpAccess)o; //轉(zhuǎn)換目標(biāo)格式
  string ret = obj.AccessVar; //獲取目標(biāo)值
  ToLua.Push(L, ret);//將目標(biāo)對象傳入虛擬機(jī)
  return 1;
 }
 catch (System.Exception e)
 {
  return LuaDLL.toluaL_exception(L, e, o, "attempt to index AccessVar on a nil value");
 }
 }
 private int SetAccesVar(System.IntPtr L)
 {
 object o = null;
 
 try
 {
  o = ToLua.ToObject(L, 1);//獲得變量實例
  CSharpAccess obj = (CSharpAccess)o;//轉(zhuǎn)換目標(biāo)格式
  obj.AccessVar = ToLua.ToString(L, 2);//將要修改的值進(jìn)行設(shè)定
  return 1;
 }
 catch (System.Exception e)
 {
  return LuaDLL.toluaL_exception(L, e, o, "attempt to index AccessVar on a nil value");
 }
 }
}

運(yùn)行結(jié)果

Lua調(diào)用C#

那么最后,我們回到本節(jié)開始, @羅夏L的文章里是哪里出現(xiàn)了問題?

我在lua中加入了一行access:PrintArg("PrintArg")調(diào)用方法,發(fā)現(xiàn)Unity報了這樣的錯誤:

直接調(diào)用方法名報錯.png

說明單純這樣是做不到直接調(diào)用方法的,仔細(xì)看文章,我發(fā)現(xiàn)他有提到這樣的內(nèi)容:

首先將自己寫的類 放到 CustomSettings 里 就是CallLuafunction

BindType[] customTypeList

放到這個數(shù)組里 注冊進(jìn)去供lua使用

這里是不是他說得不夠詳細(xì)?我找到這個類,發(fā)現(xiàn)這個類里記錄了非常多的Unity自帶類,這讓我想起了第一次啟動Lua時的提示,心里生出了一個疑問:這些數(shù)據(jù)是不是用于自動注冊生成類的呢?

 //在這里添加你要導(dǎo)出注冊到lua的類型列表
 public static BindType[] customTypeList =
 {  
 _GT(typeof(LuaInjectionStation)),
 _GT(typeof(InjectType)),
 _GT(typeof(Debugger)).SetNameSpace(null), 

...以下部分省略

沿著調(diào)用鏈,我找到了這個變量的引用,果然,最這個數(shù)據(jù)是用于類型注冊的。

我將這個類放到了數(shù)組的最后,點擊Clear wrap files,完成后立即彈出了數(shù)據(jù)自動生成的對話框,點擊確認(rèn),

重新生成注冊

自動生成

接下來我重新運(yùn)行了lua腳本:

print('--進(jìn)入Lua調(diào)用--')
local go = UnityEngine.GameObject.Find("LuaScene")
local access=go:GetComponent("CSharpAccess")
access:Debug("Lua調(diào)用C#方法")
access.AccessVar="--這是修改值--"
print('--Lua調(diào)用結(jié)束--')
access:PrintArg("PrintArg")

成功運(yùn)行

成功運(yùn)行,說明ToLua實現(xiàn)了一整套綁定方案,只需要將所需要的內(nèi)容配置完成即可。

6.總結(jié)

原本只是想簡單寫一寫調(diào)用方式,最后又寫成了一篇長文,但是從有計劃開始到一整篇結(jié)束卻花掉了近一整天的時間。

雖然如此,收獲還是非常大的,對這套工具的使用熟練度又上了一個層次,以后也要加強(qiáng)總結(jié)。

以上這篇ToLua框架下C#與Lua代碼的互調(diào)操作就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • C#面向?qū)ο笤O(shè)計原則之開閉原則

    C#面向?qū)ο笤O(shè)計原則之開閉原則

    這篇文章介紹了C#面向?qū)ο笤O(shè)計原則之開閉原則,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-03-03
  • c#泛型序列化對象為字節(jié)數(shù)組的示例

    c#泛型序列化對象為字節(jié)數(shù)組的示例

    這篇文章主要介紹了c#泛型序列化對象為字節(jié)數(shù)組的示例,需要的朋友可以參考下
    2014-04-04
  • 詳解C#設(shè)計模式編程中生成器模式的使用

    詳解C#設(shè)計模式編程中生成器模式的使用

    這篇文章主要介紹了詳解C#設(shè)計模式編程中生成器模式的使用,生成器模式主張創(chuàng)建對象的過程和對象的表現(xiàn)應(yīng)該分離開來,需要的朋友可以參考下
    2016-02-02
  • 詳解Winform里面的緩存使用

    詳解Winform里面的緩存使用

    這篇文章主要介紹了Winform里面的緩存使用,有需要的朋友可以參考一下
    2014-01-01
  • C#中標(biāo)準(zhǔn)的IDispose模式代碼詳解

    C#中標(biāo)準(zhǔn)的IDispose模式代碼詳解

    在本篇文章中小編給大家分享的是關(guān)于C#中標(biāo)準(zhǔn)的IDispose模式的實例用法相關(guān)內(nèi)容,有需要的朋友們測試下。
    2019-09-09
  • C# cefSharep控件的使用詳情

    C# cefSharep控件的使用詳情

    本文主要介紹了C# cefSharep控件的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • C#?wpf實現(xiàn)任意控件更多調(diào)整大小功能

    C#?wpf實現(xiàn)任意控件更多調(diào)整大小功能

    這篇文章主要為大家詳細(xì)介紹了C#?wpf實現(xiàn)任意控件更多調(diào)整大小功能的相關(guān)知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01
  • 如何解決hash沖突

    如何解決hash沖突

    上篇文章 為什么哈希存取比較快?使用它需要付出什么代價 只是簡單介紹了使用hash所帶來的利與弊。并未涉及hash的技術(shù)細(xì)節(jié),本文則著重學(xué)習(xí)一下如何解決哈希編址的沖突問題。
    2016-06-06
  • C#使用ToUpper()與ToLower()方法將字符串進(jìn)行大小寫轉(zhuǎn)換的方法

    C#使用ToUpper()與ToLower()方法將字符串進(jìn)行大小寫轉(zhuǎn)換的方法

    這篇文章主要介紹了C#使用ToUpper()與ToLower()方法將字符串進(jìn)行大小寫轉(zhuǎn)換的方法,實例分析了C#大小寫轉(zhuǎn)換的相關(guān)技巧,需要的朋友可以參考下
    2015-04-04
  • C#?連接本地數(shù)據(jù)庫的實現(xiàn)示例

    C#?連接本地數(shù)據(jù)庫的實現(xiàn)示例

    本文主要介紹了C#?連接本地數(shù)據(jù)庫的實現(xiàn)示例,文中根據(jù)實例編碼詳細(xì)介紹的十分詳盡,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03

最新評論