我在游戏中将回调注册为事件处理程序,如下所示:
--register event handler
EventDispatcher:register("fire", mt.onPlayerFire, self)
--this is the event handler
mt:onPlayerFire()
print("play fire")
end
--unregister event handler
EventDispachter:unregister("fire", mt.onPlayerFire, self)
当事件处理程序是模块mt
中的一个函数时,可以取消注册它,因为我可以在mt
中找到相同的函数来注销它,但是当我使用这种形式时: / p>
EventDispatcher:register("fire", function() doSomething() end, nil)
我无法取消注册事件处理程序,因为它是匿名的,因此我想在我的register
函数中添加一些检查,以防止匿名函数作为事件处理程序。
我发现lua源代码中的Proto结构可能会有所帮助,但我不知道每个部分的含义。
答案 0 :(得分:2)
我无法取消注册事件处理程序,因为它是匿名的
Lua中的每个函数都是匿名值。因此,您不能取消注册不是因为它是匿名的,而是因为您没有保存对其的任何引用。
如果传递的值(EventDispatcher:register()
类型)也保存在其他位置,则无法检测function
内部。因此,如果您确实对同一事件有多个回调,并且要注销一个特定的回调,则必须有一种方法来标识该确切的回调函数。
这意味着您应该将函数值保存在某个位置,以便稍后将其自身的值用作unregister()
的标识符,或者返回在{{1}内部生成的新回调的实例ID。 }添加回调时。无论哪种方式,register()
外部都需要存储一些内容以标识确切的回调。
答案 1 :(得分:1)
这种方式可以避免您的问题,但是仍然可以解决您的问题。
注册新的回调时,您可以简单地返回某种识别值,例如ID,表或函数本身。这样可以让您稍后取消注册。
local firehandler = EventDispatcher:register("fire", function() do('something') end)
-- Do some stuff here...
EventDispatcher:unregister(firehandler)
缺点是您可能必须更改事件分发程序跟踪其已注册事件的方式,但是最坏的情况是这意味着实现一些链接列表,并且充其量只能使用Lua表来跟踪处理程序
对于检测匿名函数,这实际上是不可能的。 Lua不会将您就地定义的功能与存储在变量中的功能区分开来。最终是同一回事。
通过使用debug
库,通过将定义函数的文件/行与调用堆栈进行比较,可能是可行的,但这只是将错误引入代码中,可能会很慢。