Lua实现C#的Get/Set属性访问器

本文介绍如何使用Lua的元表和元方法来模仿C#的get、set属性功能,通过具体代码示例展示了如何定义和使用这些属性,使Lua具备类似C#的属性访问特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

虽然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功能有以下几方面:

  1. 检查xxx字段是否是__get____set__的内部字段(__get__.xxx
  2. 调用__get__ __set__ 对应的函数
  3. 修改getset_valuesxxx的值
  4. 判断__xxx(在实例中__xxx作为属性的真实存储值,如果不想通过get或者set获取,直接instance.__xxx就不会出发对应函数)
  5. _xxx转为xxxgetset_values中找值并返回
test.lua

分割线之上是声明一个类,分割线下是测试的代码,输出结果分别对应着p1.age = 10print(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
]]
### Xlua实现C#Lua交互的方法及示例 Xlua 是 Unity 中用于实现 C#Lua 之间交互的工具,其核心功能是通过生成代码或动态反射机制,使得 Lua 脚本能够调用 C# 方法,同时 C# 也可以调用 Lua 函数。以下是详细的使用方法和示例: #### 1. Lua 调用 C# Lua 调用 C# 的方式主要分为两种:生成代码的方式和静态列表的方式。 - **生成代码方式** 如果可以访问 C# 源代码,则可以在需要被 Lua 调用的类上添加 `[LuaCallCsharp]` 标签[^1]。例如: ```csharp [XLua.LuaCallCSharp] public class MyClass { public void MyMethod() { Debug.Log("Called from Lua!"); } } ``` 在这种情况下,当需要调用 `MyClass.MyMethod` 时,Lua 脚本可以直接写为: ```lua local myClass = CS.MyClass() -- 使用 CS 命名空间访问 C# 类 myClass:MyMethod() ``` - **静态列表方式** 如果无法修改 C# 源代码(如系统 API),则可以通过静态列表注册需要暴露给 Lua 的类型[^1]。例如: ```csharp public static class LuaStaticList { public static System.Collections.Generic.List<System.Type> MyModule_LuaCallCS_List = new System.Collections.Generic.List<System.Type>() { typeof(UnityEngine.GameObject), typeof(System.Collections.Generic.Dictionary<string, int>) }; } ``` 这样,这些类型中的公共方法即可在 Lua 中直接调用。 #### 2. C# 调用 Lua C# 调用 Lua 的过程通常涉及加载 Lua 脚本并执行其中的函数。以下是一个完整的示例: - **定义 Lua 函数** 在 Lua 文件中定义一个函数,例如: ```lua function add(a, b) return a + b end ``` - **从 C# 调用 Lua 函数** 在 C# 中加载 Lua 脚本并调用该函数[^2]: ```csharp using XLua; public class LuaTest : MonoBehaviour { LuaEnv luaEnv = new LuaEnv(); void Start() { // 加载 Lua 脚本 luaEnv.DoString(@" function add(a, b) return a + b end "); // 调用 Lua 函数 var result = luaEnv.Global.Get<XLua.Function>("add").Call(3, 5)[0]; Debug.Log(result); // 输出 8 } void OnDestroy() { luaEnv.Dispose(); } } ``` #### 3. 访问 Lua 中的 Table Xlua 提供了两种方式来访问 Lua 中的 Table 数据结构:映射到类和映射到接口[^4]。 - **映射到类** 将 Lua Table 映射为 C# 类时,数据会被拷贝到 C# 端,因此对 C# 对象的修改不会影响 Lua 中的数据。 ```lua local myTable = { name = "XLua", version = "2.0" } ``` ```csharp public class MyTable { public string name; public string version; } MyTable table = luaEnv.New<MyTable>(myTable); Debug.Log(table.name); // 输出 XLua ``` - **映射到接口** 将 Lua Table 映射为接口时,数据以引用形式传递,因此对 C# 端的修改会同步到 Lua 中。 ```lua local myTable = { name = "XLua", version = "2.0" } ``` ```csharp public interface IMyTable { string name { get; set; } string version { get; set; } } IMyTable table = luaEnv.New<IMyTable>(myTable); table.name = "NewName"; Debug.Log(myTable.name); // 输出 NewName ``` #### 4. 注意事项 - **重载函数问题** Lua 的类型系统不如 C# 丰富,因此在调用重载函数时可能会出现冲突。建议尽量避免使用重载函数,或者明确指定参数类型[^3]。 - **默认值和可变参数** 参数带默认值的方法和可变参数方法在 Lua 中可能无法正确解析。需要确保这些方法在 Lua 脚本中被正确调用[^3]。 - **异常处理** 当 Lua 脚本调用 C# 方法时,如果方法不存在或签名不匹配,可能会抛出异常。需要在开发过程中注意测试和调试。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值