日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

SLua 中继承 C# 类接口 Slua.Class 的一个 Bug。

發布時間:2025/5/22 C# 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SLua 中继承 C# 类接口 Slua.Class 的一个 Bug。 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  由于目前要把大量的代碼移植到 lua 中(真是夠虐心的),面向對象肯定少不了,項目的代碼都是這么設計的,于是就測試 Slua.Class 接口來擴展 C# 的類,發現有點問題,給作者提交了一個 Issue 和 一個 Pull Request,作者也很快確認并 Merge 了。

  問題是這樣:當使用 Slua.Class 繼承出來的類,實例化出來的所有實例都指向了最后一個實例,導致訪問屬性都是一樣的。比如使用 main.txt 中得一段代碼修改測試:

-- test inherite class local mv = My2(1, 2, 3) local mv_2 = My2(4, 5, 6) -- I add for test. mv:Normalize() mv_2:Normalize() -- I add for test. print("mv norm:", mv.x, mv.y, mv.z) -- I modified for test. print("mv_2 norm:", mv_2.x, mv_2.y, mv_2.z) -- I add for test. mv:Set(10, 20, 30) -- I modified for test. mv_2:Set(40, 50, 60) -- I add for test. print("mv:", mv.x, mv.y, mv.z) -- I add for test. print("mv_2:", mv_2.x, mv_2.y, mv_2.z) -- I add for test.

結果將輸出如下:

mv norm: 0.62469504755442 0.78086880944303 0.93704257133164 mv_2 norm: 0.62469504755442 0.78086880944303 0.93704257133164 mv: 40 50 60 mv_2: 40 50 60

  在以上結果中,My2 的實例 my, my_2 構造的值是不同的,但輸出相同的結果。看看 Slua.Class 的代碼,在 Helper.cs 中:

local getmetatable=getmetatable local function Class(base,static,instance)local mt = getmetatable(base)local class=static or {}setmetatable(class, {__call=function(...)local r = mt.__call(...)local ret = instance or {}ret.__base=rlocal ret = setmetatable(ret,{__index=function(t,k)return r[k]end,__newindex=function(t,k,v)r[k]=vend,})return retend,})return class end return Class

  以上代碼中,ret 是類的模板,用來為各個實例化對象提供方法和屬性,不應該被構造時返回(而且上面每次構造都返回了相同的一個 ret),但是 ret 應該是大家 shaderd,構造返回的對象應該是一個新構造的對象,且 __index 為 ret,這樣既能獲取派生類的各種方法屬性,又不會不小心修改 ret。

  同時,我做了如下的一些小修改:

  • 可以直接使用派生類調用積累的靜態成員方法,如基類 Base.ShowStatic(),那么派生類可以直接使用:Derived.ShowStatic();
  • 增加了一個名為 ctor 的可選構造函數(這個借鑒了云風給出的 lua-oop 方案);
  • 保持通過訪問父類方法使用 __base,但注意不用使用這個來訪問父類成員變量,因為當你第一次在派生類訪問父類變量,會被復制到派生類,所以可能會訪問到錯誤的數據,只有派生類的才是有效的。
  •   修改完的代碼如下:

    local getmetatable = getmetatable local function Class(base,static,instance)local mt = getmetatable(base)local class = static or {}setmetatable(class, {__index = base,__call = function(...)local r = mt.__call(...)local ret = instance or {}local ins_ret = setmetatable({__base = r,},{__index = function(t, k)local ret_fieldret_field = ret[k]if nil == ret_field thenret_field = r[k]endt[k] = ret_fieldreturn ret_fieldend,})if ret.ctor thenret.ctor(ins_ret, ...)endreturn ins_retend,})return class end return Class

      使用跟以前一樣,但可以增加一個構造函數:

    MyVector3 = Slua.Class(Vector3, { }, {-- This is optional.ctor = function(self)print("Do something...")end, })

      但是我覺得還是有點小問題,以上書寫新的擴展類代碼的時候不是太方便,不能分開單獨寫每個成員變量和函數,也可以墻紙分開,但命名上不太好看,于是我自己又做了如下修改:

    local getmetatable = getmetatable local function Class(base)local mt = getmetatable(base)local class = {}class.ctor = falsesetmetatable(class, {__index = base,__call = function(...)local r = mt.__call(...)local ins_ret = {__base = r,}setmetatable(ins_ret,{__index = function(t, k)local ret_fieldret_field = rawget(class, k)if nil == ret_field thenret_field = r[k]if 'function' == type(ret_field) thenclass[k] = ret_fieldelseins_ret[k] = ret_fieldendendreturn ret_fieldend,})if class.ctor thenclass.ctor(ins_ret, ...)endreturn ins_retend,})return class end return Class

    這樣的話,我就可以更方便的定義類,符合以前的書寫習慣,同時,優化一下,當訪問派生類不存在的的父類成員時,之拷貝函數,不拷貝成員變量,以免浪費空間。這樣我可以這樣書寫:

    MyVector3 = Slua.Class(Vector3)-- Constructor, optional. function MyVector3:ctor()print("Do something!") end-- Instance method. function MyVector3:Normaize()--Do your own normalize. end-- Static method. function MyVector3.PrintMyNameprint("MyVector3") end

      但作者說如果不是 bug,只是為了方便,最后這個不能修改,因為要考慮兼容性,已經有人這么用了,確實是這樣,所以我就把這個提交到自己的另一個分支里,在自己的項目使用新方法。

    轉載于:https://www.cnblogs.com/yaukey/p/4545093.html

    總結

    以上是生活随笔為你收集整理的SLua 中继承 C# 类接口 Slua.Class 的一个 Bug。的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。