xlua中lua对象到c#对象的转型

lua中的类型
基础类型

#define LUA_TNIL 0
#define LUA_TBOOLEAN 1
#define LUA_TLIGHTUSERDATA 2
#define LUA_TNUMBER 3
#define LUA_TSTRING 4
#define LUA_TTABLE 5
#define LUA_TFUNCTION 6
#define LUA_TUSERDATA 7
#define LUA_TTHREAD 8
变体(或者说子类型)

/*
** tags for Tagged Values have the following use of bits:
** bits 0-3: actual tag (a LUA_T* value)
** bits 4-5: variant bits
** bit 6: whether value is collectable
*/

/*
** LUA_TFUNCTION variants:
** 0 - Lua function
** 1 - light C function
** 2 - regular C function (closure)
*/

/* Variant tags for functions /
#define LUA_TLCL (LUA_TFUNCTION | (0 << 4)) /
Lua closure /
#define LUA_TLCF (LUA_TFUNCTION | (1 << 4)) /
light C function /
#define LUA_TCCL (LUA_TFUNCTION | (2 << 4)) /
C closure */

/* Variant tags for strings /
#define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /
short strings /
#define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /
long strings */

/* Variant tags for numbers /
#define LUA_TNUMFLT (LUA_TNUMBER | (0 << 4)) /
float numbers /
#define LUA_TNUMINT (LUA_TNUMBER | (1 << 4)) /
integer numbers */

/* Bit mark for collectable types */
#define BIT_ISCOLLECTABLE (1 << 6)
  lua中的对象都是用TValue来描述的,TValue中的tt_成员变量代表着这个TValue的类型。关于类型的具体定义,上面贴的代码中的注释中已经讲的比较清楚了。
  一个lua对象的类型是由一个7位的bits描述的。比如一个整数,这个对象的类型就是0011000(24)表示这个对象是数字类型中的整形,是一个不可回收对象。

C#如何获取lua对象
  和c语言和lua交互其实没啥本质区别,就是通过lua提供的c函数操作lua栈,直接从栈中取就可以了。区别在于如何把取到的值转换为c#认识的值。

如何在C#端描述这些类型
简介
  lua的类型中boolean、string、number这几个类型是clr所认识的类型,所以clr就可以直接把这些类型拿过来用。具体就是直接调用Lua提供的lua_tonumber之类的c接口。
  lightUserData、table、function、userData、thread是C#不认识的类,需要通过某种标识(lua自带的reference系统)来表示。

boolean、string、number类
  这三个类上面已经说过了,直接用提供的接口转就可以,下面写几个需要注意的点:

string虽然也是一个引用类型,但是clr在拿到这个string的指针时,还需要将这个string的数据直接复制进clr中才算转型结束(xlua也已经封装好了,不用我们自己去复制)。
大部分类型转型失败的时候都不会报错,而是会返回一个默认值。就拿将一个lua对象转为int来说,最终是通过lua_tointegerx函数调用的,当lua对象不是number类型时,返回0:
LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) {
lua_Integer res;
const TValue o = index2addr(L, idx);
int isnum = tointeger(o, &res);
if (!isnum)
res = 0; /
call to ‘tointeger’ may change ‘n’ even if it fails */
if (pisnum) pisnum = isnum;
return res;
}
当一个number类型是浮点数时,转型整数不会进行取整操作,而是会直接返回0。因为lua默认对float转int的操作模式LUA_FLOORN2I是0,代表碰见float转int时返回0。
/

** try to convert a value to an integer, rounding according to ‘mode’:
** mode == 0: accepts only integral values
** mode == 1: takes the floor of the number
** mode == 2: takes the ceil of the number
*/
int luaV_tointeger (const TValue *obj, lua_Integer p, int mode) {
TValue v;
again:
if (ttisfloat(obj)) {
lua_Number n = fltvalue(obj);
lua_Number f = l_floor(n);
if (n != f) { /
not an integral value? /
if (mode == 0) return 0; /
fails if mode demands integral value /
else if (mode > 1) /
needs ceil? /
f += 1; /
convert floor to ceil (remember: n != f) */
}
return lua_numbertointeger(f, p);
}
else if (ttisinteger(obj)) {
p = ivalue(obj);
return 1;
}
else if (cvt2num(obj) &&
luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {
obj = &v;
goto again; /
convert result from ‘luaO_str2num’ to an integer /
}
return 0; /
conversion failed */
}
userData
  userData主要是lua对c#对象的引用,这里只简单说一下。
  代表c#对象的userData主要分两种。

把c#对象存在ObjectTranslator中,用下标作为引用(类似于lua中的reference)。
经过GC优化的结构体和枚举,不存在ObjectTranslator中,而是把所有内容都打包到userdata中一起传入lua中。比如一个Vector3,那么xlua会把这个Vector3的x、y、z作为3个连续的float一起打包到userdata中。这样就避免了c#层的装箱、拆箱和gc操作。
对table与function的引用简介
  这两个类型都是通过lua的reference系统来让c#持有对lua对象的引用。

lua reference系统
  c#就是通过这个系统来持有不认识的lua对象的。
  一共就两个接口:

luaL_ref:把栈顶元素加入一个lua的表中,并返回下标。
luaL_unref:把一个下标所代表元素从表中删除。
  这样就可以用一个整数来让lua外的环境持有这个lua对象。
具体可以看下官方说明lua References

luaBase类
  所有lua对象在c#中的基类,在初始化时通过luaL_ref生成lua对象的引用,在析构时通过luaL_unref移除引用。

对table的引用
LuaTable
  一般情况下table在C#中被包装为LuaTable类,没啥特别的,只是在LuaBase的基础上增加了几个常用的函数。比如Get、Set之类的,让开发者可以避开一些不直观的栈操作。

Array、List、Dictionary
  这几个都差不多。都是把table中的key和value全部拿出来,组成Array或Dictionaray。

接口、其他类
  这两种转型是尝试把这个table看作对应的接口或类。
  比如将一个table转为IEnumberator就是把table转为SystemCollectionsIEnumeratorBridge类(继承了LuaBase、实现了IEnumerator的类,由Xlua生成),这个类实现了MoveNext和Reset。实现方法就是调用一下table中对应名称的函数。

对function的引用
  lua函数在c#中有两种表示:

LuaFunction
  LuaFunction和luaTable差不多,也是在LuaBase的基础上增加了几个常用函数,Call、Action之类的。

DelegateBridge
  为什么已经有LuaFunction还要一个DelegateBridge类?
  因为我们在c#中拿到一个lua函数时,大多数时候是要作为一个委托来时用的。DelegateBridge就是用来化简这个转型操作的。
  DelegateBridge的功能就是在持有lua函数引用的同时,将这个函数包装成各种各样的委托,让整个转型过程对开发人员无感知。
  下面是一个不使用DelegateBridge,自己转型的例子,比较繁琐:

//将一个LuaFunction作为一个Action使用
//其实LuaFunction.Cast就是干这个的,这里只是用简单的方式表达出来
public static Action LuaFunctionToActionInt(XLua.LuaFunction luaFunction)
{
//由于luaFunction已经提供了Call操作封装了函数调用的各种栈操作,所以我们这里只需要用一个Action把这个操作包装起来即可
return (x) =>
{
luaFunction.Call(x);
};
}

public static void Test()
{
XLua.LuaEnv luaEnv = new XLua.LuaEnv();
object[] rets = luaEnv.DoString("return function(x) CS.UnityEngine.Debug.LogError("print x: “…x) end”);
var luaFunction = (XLua.LuaFunction)rets[0];
Action actionInt = LuaFunctionToActionInt(luaFunction);
actionInt(10);
}
DelegateBridge重要成员

xlua在将lua函数转型的时候做了什么

Tips
通过ObjectTranslator.getDelegateUsingGeneric生成委托时,会对返回值和参数进行不为值类型的约束。因为值类型在il2cpp下会有jit异常。这也是为什么我们发现有的委托类型不用注册也可以使用,但是有的就不行。
在编辑器模式下,没有进行代码生成时,会通过Emit直接生成一个XLuaGenDelegateImplx类,内容和通过代码生成后的DelegateBridge一样,而不是全部通过反射来进行转型。让没有进行代码生成时的环境和真机环境更接近。
DelegateBridge一般不会被直接引用,而是被bindto中的委托生成的闭包引用和被delegate_bridges作为弱引用持有。当一个DelegateBridge的bindto中的委托没有被任何对象引用时,这个DelegateBridge就会在下次gc时被gc掉。
其他
  这里主要写了常用lua类型转型的简介和一些关键点。可能不够全面和细节。
  如果有什么错误或者问题可以在下面留言。
  https://mvp.leju.com/article/6664050187411479522.html
https://mvp.leju.com/article/6664050177294818273.html
https://mvp.leju.com/article/6664050160865729217.html
https://mvp.leju.com/article/6664050147246824414.html
https://mvp.leju.com/article/6664353930308835959.html
https://mvp.leju.com/article/6664353824201332736.html
https://mvp.leju.com/article/6664353813472304127.html
https://mvp.leju.com/article/6664353741711956981.html
https://mvp.leju.com/article/6664353736418745305.html
https://mvp.leju.com/article/6665870150875043990.html
https://mvp.leju.com/article/6665870142234777748.html
https://mvp.leju.com/article/6665870133246384940.html
https://mvp.leju.com/article/6665870121670105899.html
https://mvp.leju.com/article/6665870064912783498.html
https://mvp.leju.com/article/6666245326569560549.html
https://mvp.leju.com/article/6666245309129644516.html
https://mvp.leju.com/article/6666245299415636446.html
https://mvp.leju.com/article/6666245289093454730.html
https://mvp.leju.com/article/6666245276422461915.html
https://mvp.leju.com/article/6666537285251062118.html
https://mvp.leju.com/article/6666537269170100383.html
https://mvp.leju.com/article/6666536851610359926.html
https://mvp.leju.com/article/6666536839623039091.html
https://mvp.leju.com/article/6666536827044321393.html
https://mvp.leju.com/article/6666949382812294065.html
https://mvp.leju.com/article/6666949362348284847.html
https://mvp.leju.com/article/6666949357021518828.html
https://mvp.leju.com/article/6666949347974405099.html
https://mvp.leju.com/article/6666949153379670331.html
https://mvp.leju.com/article/6667314430810347750.html
https://mvp.leju.com/article/6667314407628429692.html
https://mvp.leju.com/article/6667314325931776226.html
https://mvp.leju.com/article/6667314313575356640.html
https://mvp.leju.com/article/6667314292318623967.html
https://mvp.leju.com/article/6667725731000834137.html
https://mvp.leju.com/article/6667725534887762008.html
https://mvp.leju.com/article/6667725524800460886.html
https://mvp.leju.com/article/6667725512653757291.html
https://mvp.leju.com/article/6667725491736763241.html
https://mvp.leju.com/article/6668079910491872141.html
https://mvp.leju.com/article/6668079903156034442.html
https://mvp.leju.com/article/6668079893777570697.html
https://mvp.leju.com/article/6668079883677686663.html
https://mvp.leju.com/article/6668079871895886725.html
https://mvp.leju.com/article/6668352776504433058.html
https://mvp.leju.com/article/6668352691334896174.html
https://mvp.leju.com/article/6668352563400235565.html
https://mvp.leju.com/article/6668352478713043361.html
https://mvp.leju.com/article/6668352391127587372.html
https://mvp.leju.com/article/6669433654945077945.html
https://mvp.leju.com/article/6669488087775139889.html
https://mvp.leju.com/article/6669488078455396399.html
https://mvp.leju.com/article/6669488071568349229.html
https://mvp.leju.com/article/6669488061539769101.html
https://mvp.leju.com/article/6669797109384435910.html
https://mvp.leju.com/article/6669797118343469928.html
https://mvp.leju.com/article/6669797054942370632.html
https://mvp.leju.com/article/6669797096801523907.html
https://mvp.leju.com/article/6669797852250200955.html
https://mvp.leju.com/article/6670571022485904096.html
https://mvp.leju.com/article/6670571010880264769.html
https://mvp.leju.com/article/6670571005037599452.html
https://mvp.leju.com/article/6670570986914011785.html
https://mvp.leju.com/article/6670570969671228119.html
https://mvp.leju.com/article/6671734749528676449.html
https://mvp.leju.com/article/6671734730482342595.html
https://mvp.leju.com/article/6671734714804034531.html
https://mvp.leju.com/article/6671734696135187426.html
https://mvp.leju.com/article/6671734678150011586.html
https://mvp.leju.com/article/6672035491225361302.html
https://mvp.leju.com/article/6672035330273139555.html
https://mvp.leju.com/article/6672035235758692867.html
https://mvp.leju.com/article/6672035146042529860.html
https://mvp.leju.com/article/6672035069433567824.html
https://mvp.leju.com/article/6672696224980228202.html
https://mvp.leju.com/article/6672695830765984179.html
https://mvp.leju.com/article/6672695821383326130.html
https://mvp.leju.com/article/6672695809513445839.html
https://mvp.leju.com/article/6672695788663560654.html
https://mvp.leju.com/article/6673125353252804824.html
https://mvp.leju.com/article/6673125306238851743.html
https://mvp.leju.com/article/6673125238534396102.html
https://mvp.leju.com/article/6673125176345451418.html
https://mvp.leju.com/article/6673125072226048659.html
https://mvp.leju.com/article/6673479165071153935.html
https://mvp.leju.com/article/6673479118732482572.html
https://mvp.leju.com/article/6673479081755499070.html
https://mvp.leju.com/article/6673479020887759333.html
https://mvp.leju.com/article/6673479147274721968.html
https://mvp.leju.com/article/6673786454395148554.html
https://mvp.leju.com/article/6673784837868443828.html
https://mvp.leju.com/article/6673783310273566814.html
https://mvp.leju.com/article/6673783160864069715.html
https://mvp.leju.com/article/6673783086046075661.html
https://mvp.leju.com/article/6674221253207350251.html
https://mvp.leju.com/article/6674221243963103368.html
https://mvp.leju.com/article/6674221234702081012.html
https://mvp.leju.com/article/6674221221443885700.html
https://mvp.leju.com/article/6674221181816100992.html
https://mvp.leju.com/article/6674508925624736749.html
https://mvp.leju.com/article/6674508900886731429.html
https://mvp.leju.com/article/6674508774134864428.html
https://mvp.leju.com/article/6674508764173392427.html
https://mvp.leju.com/article/6674508680476056222.html
https://mvp.leju.com/article/6674911143674862495.html
https://mvp.leju.com/article/6674910938606951322.html
https://mvp.leju.com/article/6674910811125274638.html
https://mvp.leju.com/article/6674910742691010665.html
https://mvp.leju.com/article/6674910587162024851.html
https://mvp.leju.com/article/6675660308700813932.html
https://mvp.leju.com/article/6675660286743632762.html
https://mvp.leju.com/article/6675660269702174975.html
https://mvp.leju.com/article/6675660249347218293.html
https://mvp.leju.com/article/6675660227729775211.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值