- tolua中c#和lua交互過的對象都有一個ref編號, ref是int類型,ref唯一不重復,一個ref對應一個c#對象
- tolua中任何c#對象在lua中對應的userdata都是一個int類型的內存指針地址,通過對這個userdata設置不同的metatable來區分userdata對應的c#類型
- 這個userdata指針指向的int內存的值等於第1條的ref值,比如有個c#對象的ref等於13,那么userdata指針指向的內存的值就等於13
- userdata在lua中被緩存在一個叫ubox的弱表里,userdata在ubox的下標等於c#對象對應的ref,比如有個c#對象的ref等於13,那么這個c#對象的userdata在ubox的下標就是13,如果一個userdata只被ubox指向,那么這個userdata會被GC
- tolua中一個c#對象被首次push進lua中,會申請一塊內存,大小為sizeof(int),userdata就是指向這塊內存的指針,並且調用lua_setfenv把userdata的環境表設置為TOLUA_NOPEER,調用lua_setmetatable把userdata的元表設置為c#對象在lua中特定的一個table(每個被bind的c#對象都會有一個對應的meta表,這個meta表存放着c#對象對應的方法的指針)
- tolua Bind注冊一個c#類,假設這個c#類叫A類,會創建一個對應的metatable,我們叫這個metatable為mtA,A類的wrap文件的static方法會對應的賦值給mtA。當tolua要push一個A類到lua是,會創建一個userdata,並且設置userdata的metatable為mtA。mtA的__index元方法等於一個叫class_index_event的luacfunction。因為userdata什么都沒有,所以訪問userdata的成員的時候,會調用class_index_event,class_index_event的訪問規則如第7條。
- 訪問一個userdata成員,比如userdata.name,會進行如下步驟:
- 先直接在userdata的環境表peer找,value = rawget(peer, name),value不為nil則直接否則返回value賦值給userdata.name,下面的步驟都不用執行了。value為nil則進行第2步。
- 在peer的gettable找,gettable = peer[&gettag],如果rawget(gettable, name)是一個function(luafunction或者cfunction)則call這個function,function的返回值賦值給userdata.name。否則,進行第3步。
- 如果peer有元表,則在peer的元表重復1,2,3步驟,peer沒有元表則進行第5步。(注意是在peer的元表上查找,而不是元表的__index查找)
- 在userdata的元表umt找,如果name是一個number類型,說明userdata可能是一個Array類型,則在value = umt[".geti"]找,如果value為function(luafunction或者cfunction)則call這個function,function的返回值賦值給userdata.name。如果name不是number類型,則value = rawget(umt, name),value不為nil,返回value,value為nil,進行第5步
- 在umt的gettable找,gettable = umt[&gettag],如果rawget(umt, name)是一個function(luafunction或者cfunction)則call這個function,function的返回值賦值給userdata.name。否則,進行第6步。
- 如果umt有元表,則在umt的元表重復4,5,6步驟,umt沒有元表則進行第7步。(注意是在umt的元表上查找,而不是元表的__index查找)
- 到了這一步還找不到,會判斷userdata == LUA_NULL_USERDATA,如果是,則拋出異常"attemp to index %s on a nil value",否則進行第8步
- if (toluaflags & FLAG_INDEX_ERROR),拋出異常"field or property %s does not exist"