Lua开发者运行: 1909天

Lua中实现类似C#的事件机制

作者:LuaStudio 发布于:2015-12-27 9:33 Sunday 分类:新手教程

Lua的语法非常灵活, 使用他的metatable及metamethod可以模拟出很多语言的特性.
  C#中我们这样使用事件:
  1. xxx.Click += new System.EventHandler(xxx_Click);
  2.   private void xxx_Click(object sender, EventArgs e)
  3.   {
  4.   /**/
  5.   }
复制代码
在Lua中要达到同样的效果, 并且支持事件多播机制, 其关键在于重写metamethod __call, 从而使得不光function才能被调用, table也能够被调用.
  主要思想就是, 通过一个table来保存注册事件的若干响应函数, 然后拿table当function一样来调用, 重写__call后, 实现调用table时遍历执行table中的注册方法.
  需要在lua5.0 或 lua.net上执行, lua 5.1略有改动.
  切换行号显示
  1. --test.lua
  2.    do
  3.   
  4.    --事件原型对象, 所有事件由此原型生成
  5.    Event = {}
  6.   
  7.    function Event:New()
  8.    local event = {}
  9.    setmetatable(event, self)
  10.    --覆盖__index逻辑
  11.    self.__index = self
  12.    --覆盖__call逻辑
  13.    self.__call = self.Call
  14.    return event
  15.    end
  16.   
  17.    --事件注册, 通过此方法将响应方法注册到事件上.
  18.    --@source:响应方法的所属对象
  19.    --@func:响应方法
  20.    function Event:Add(source, func)
  21.    table.insert(self, {source, func})
  22.    end
  23.   
  24.    --内部方法, 重写了默认__call逻辑, 当event被触发调用时, 循环执行event中注册的响应方法
  25.    --@table:对象产生调用时将本身传入
  26.    --@...:调用参数
  27.    function Event.Call(table, ...)
  28.    for _, item in ipairs(table) do
  29.    --item[1]就是source, item[2]就是func响应方法
  30.    --lua 5.1中无需使用unpack(arg), 直接使用...即可
  31.    item[2](item[1], unpack(arg))
  32.    end
  33.    end
  34.   
  35.    ------------------以下为测试用例-----------------------
  36.   
  37.    --创建一个window对象, 注册按钮的点击事件
  38.    Window = {
  39.    Name = "Simonw's Window",
  40.    }
  41.   
  42.    function Window:Init()
  43.    --注册事件, self即Window, 对象来源.
  44.    Button.ClickEvent:Add(self, self.Button_OnClick)
  45.    end
  46.   
  47.    --响应事件方法, sender即是传来的Button对象
  48.    function Window:Button_OnClick(sender)
  49.    print(sender.Name.." Click On "..self.Name)
  50.    end
  51.   
  52.    --创建一个button对象, 拥有ClickEvent这样的事件
  53.    Button = {
  54.    Name = "A Button",
  55.    --创建事件
  56.    ClickEvent = Event:New(),
  57.    }
  58.   
  59.    --执行点击按钮的动作
  60.    function Button:Click()
  61.    print('Click begin')
  62.    --触发事件, self即sender参数
  63.    self.ClickEvent(self)
  64.    print('Click end')
  65.    end
  66.   
  67.    --从这里执行
  68.    Window:Init()
  69.    Button:Click()
  70.    --[[
  71.    执行结果:
  72.    > dofile 'test.lua'
  73.    Click begin
  74.    A Button Click On Simonw's Window

  75.    Click end
  76.    ]]
  77.   
  78.    end

热烈欢迎各位留言,本人会虚心听取各位意见!