雖然Lua沒有C#一樣的屬性,但是它的強大的元表和元方法能夠實現很多功能,本篇博客就介紹如何用lua的元表和原方法實現C#中的get、set屬性訪問其功能。
class.lua
class.lua是實現lua的類,我的之前博客有些過簡易版的,屬性訪問的的實現相當於在最簡易版的基礎上進行擴展,博客鏈接:Lua 實現C#中的類
local mt = {}
function class(clsName, base)
local cls = {}
base = base or mt
cls.__get__ = {}
cls.__set__ = {}
setmetatable(cls, {__index = base})
cls.clsName = clsName or "default"
cls.base = base
cls.new = function(...)
local cls_instance = {}
cls_instance.getset_values = {}
for k,v in pairs(cls) do
cls_instance[k] = v
end
local cls_instance_mt = {
__index = function(t, k)
if cls[k] then
return cls[k]
end
if t.__get__[k] then
t.__get__[k](t)
return t.getset_values[k]
end
if string.sub(k, 1, 2) == "__" then
local tmpK = string.sub(k, 3, -1)
if t.getset_values[tmpK] then
return t.getset_values[tmpK]
end
end
end,
__newindex = function(t, k, v)
if t.__set__[k] then
t.__set__[k](t, v)
cls_instance.getset_values[k] = v
return
end
if string.sub(k, 1, 2) == "__" then
local tmpK = string.sub(k, 3, -1)
if t.getset_values[tmpK] then
t.getset_values[tmpK] = v
end
end
rawset(t, k, v)
end
}
setmetatable(cls_instance, cls_instance_mt)
if cls_instance.onCreate then
cls_instance:onCreate(...)
end
return cls_instance
end
return cls
end
重要擴展方式是給cls_instance
添加了一個metatable
,這個metatable
功能有以下幾方面:
- 檢查
xxx
字段是否是__get__
和__set__
的內部字段(__get__.xxx
) - 調用
__get__
__set__
對應的函數 - 修改
getset_values
中xxx
的值 - 判斷
__xxx
(在實例中__xxx
作爲屬性的真實存儲值,如果不想通過get
或者set
獲取,直接instance.__xxx
就不會出發對應函數) - 將
_xxx
轉爲xxx
去getset_values
中找值並返回
test.lua
分割線之上是聲明一個類,分割線下是測試的代碼,輸出結果分別對應着p1.age = 10
到print(p1.__age)
的每行輸出
local Person = class("Person")
Person.onCreate = function(self, name)
self.name = name
end
Person.__get__.age = function(self)
print(self.name, " - 屬性訪問器:get age")
end
Person.__set__.age = function(self, value)
print(self.name, " - 屬性訪問器:set age", value)
end
-----------------------------------
local p1 = Person.new("張三")
p1.age = 10
local tmpAge = p1.age
p1.age = p1.__age + 1
print(p1.__age)
--[[
張三 - 屬性訪問器:set age 10
張三 - 屬性訪問器:get age
張三 - 屬性訪問器:set age 11
11
]]