因為工作需求,準備開始學習 C#,這兩天研究一些公開的 Unity 原始碼發現 C# 有個 Delegate Type 很有意思,它可以利用 + 與 - 將需要搭配執行的 function 指派到委任者然後一起執行。如:
參考資料:使用委派 (C# 程式設計手冊)
Edit: 03, 08, 2015, 感謝 fb@shanyungyang 的提醒可以使用 Lua 的 metamethod 實作,為了達到屬性能往下傳,本來是打算採用 * / 但是又怕太混亂,最後就是由另外一個 meta2 來達到效果囉! ^^
FuncDelegate2.lua
這樣拿來組合執行函式實在很方便,所以為了可以在 CoronaSDK 內使用,利用 Lua table 簡單實作類似行為。(當然是沒有辦法寫 + and -,如果不像的話,就是我只實作自己想要的功能啊...XD)
FuncDelegate.lua
//C#, d1 and d2 are functions
allMethodsDelegate += d1;
allMethodsDelegate += d2;
allMethodsDelegate(); // d1(), d2()
allMethodsDelegate -= d2;
allMethodsDelegate(); // d1()
參考資料:使用委派 (C# 程式設計手冊)
Edit: 03, 08, 2015, 感謝 fb@shanyungyang 的提醒可以使用 Lua 的 metamethod 實作,為了達到屬性能往下傳,本來是打算採用 * / 但是又怕太混亂,最後就是由另外一個 meta2 來達到效果囉! ^^
FuncDelegate2.lua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
------------------------------------- | |
-- function delegate part 2 | |
-- Author: Erin Lin | |
-- www.erinylin.com | |
-- 簡易模擬 C# delegate | |
-- licensed under the MIT license. | |
-- 2015, 03 | |
-- 參考:https://gist.github.com/anonymous/3f0e5b046bfdcfa9864a | |
------------------------------------- | |
local next = next | |
local unpack = unpack | |
local t = { | |
remove = table.remove, | |
insert = table.insert, | |
indexOf = function(list, value) | |
local n = 0 | |
for k, v in next, list do | |
if v==value then return k end | |
end | |
return -1 | |
end | |
} | |
local meta = { | |
__add = function(x, y) | |
if type(y) == "function" then | |
t.insert(x, y) | |
return x | |
elseif type(y) == "table" then | |
for i=1,#y do | |
if type(y[i]) == "function" then t.insert( x, y[i] ) end | |
end | |
return x | |
end | |
end, | |
__sub = function(x, y) | |
if type(y) == "function" then | |
local index = t.indexOf( x, y ) | |
if index > -1 then t.remove( x, index ) end | |
return x | |
elseif type(y) == "table" then | |
for i=#y,1,-1 do | |
local index = t.indexOf( x, y[i] ) | |
if index > -1 then t.remove( x, index ) end | |
end | |
return x | |
end | |
end, | |
__call = function(d, ...) | |
for i,v in next, d do | |
v(...) | |
end | |
end | |
} | |
local meta2 = { | |
__add = meta.__add, | |
__sub = meta.__sub, | |
__call = function( d, ... ) | |
local result = arg or {} | |
for i,v in next, d do | |
result = { v( unpack(result) ) } | |
end | |
return unpack(result) | |
end | |
} | |
local function newDelegate( bool ) | |
local d = {} | |
--bool==false, use same arguments for every function | |
--bool==true, will pass retrun result to next function | |
setmetatable(d, bool and meta2 or meta) | |
return d | |
end | |
------------------------------------- | |
-- | |
------------------------------------- | |
local function step1( n ) | |
print("Step1", n, n + 10 ) | |
return n + 10 | |
end | |
local function step2( n ) | |
print("Step2", n, n + 20 ) | |
return n + 20 | |
end | |
local function step3( n ) | |
print("Step3", n, n + 30 ) | |
return n + 30 | |
end | |
local d = newDelegate() | |
local d2 = newDelegate( true ) | |
d = d + { step3, step2 } | |
d2 = d2 + { step1, step2, step3 } | |
print("d(0):") | |
d( 0 ) | |
d = d - step2 | |
print("d = d - step2 ; d(0)") | |
d( 0 ) | |
print("d2( 100 ):") | |
d2( 100 ) | |
print("-----------------") | |
d2 = d2 - step2 | |
print("d2 = d2 - step2 ; d2(100)") | |
d2( 100 ) |
FuncDelegate.lua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
------------------------------------- | |
-- function delegate | |
-- Author: Erin Lin | |
-- www.erinylin.com | |
-- 簡易模擬 C# delegate | |
-- licensed under the MIT license. | |
-- 2015, 02 | |
------------------------------------- | |
--[[ | |
Usage1: | |
local function step1() | |
print("Step1") | |
end | |
local function step2() | |
print("Step2") | |
end | |
local function step3() | |
print("Step3") | |
end | |
local delegate = require("FuncDelegate").new() | |
delegate:insert( step1 ):insert( step2 ):insert( step3 ) | |
-- Output: | |
-- Step1 | |
-- Step2 | |
-- Step3 | |
Usage 2: | |
local function step1( n ) | |
print("Step1", n ) | |
return n + 10 | |
end | |
local function step2( n ) | |
print("Step2", n ) | |
return n + 20 | |
end | |
local function step3( n ) | |
print("Step3", n ) | |
return n + 30 | |
end | |
local delegate = require("FuncDelegate").new() | |
delegate:insert( step1 ):insert( step2 ):insert( step3 ) | |
print("delegate:run( 0 ) =", delegate:run( 0 ) ) | |
print("delegate:runWithSameArgs( 0 ) =", delegate:runWithSameArgs( 0 ) ) | |
-- Output: | |
-- Step1 0 | |
-- Step2 10 | |
-- Step3 30 | |
-- delegate:run( 0 ) = 60 | |
-- Step1 0 | |
-- Step2 0 | |
-- Step3 0 | |
-- delegate:runWithSameArgs( 0 ) = 10 | |
--]] | |
local M = { | |
_pool = {} | |
} | |
local M_mt = {__index=M} | |
local unpack = unpack | |
local t = { | |
remove = table.remove, | |
insert = table.insert, | |
indexOf = function(list, value) | |
local n = 0 | |
for k, v in next, list do | |
if v==value then return k end | |
end | |
return -1 | |
end | |
} | |
function M:insert( element ) | |
assert( type(element)=="function", "argument must be a type of function") | |
local index = t.indexOf( self._pool, element ) | |
if index<0 then | |
t.insert( self._pool, element ) | |
end | |
return self | |
end | |
function M:remove( element ) | |
local index = t.indexOf( self._pool, element ) | |
if index > -1 then | |
t.remove( self._pool, index ) | |
end | |
return self | |
end | |
-- will pass retrun result to next function | |
-- 會將前一個函式的回傳值傳到下一個函式,但是如果都是無回傳,用 run or runWithSame 都無所謂 | |
function M:run( ... ) | |
local result = arg or {} | |
for i=1,#self._pool do | |
result = { self._pool[i](unpack( result )) } | |
end | |
return unpack( result ) | |
end | |
-- use same arguments for every function | |
-- 全部函式都用一開始的傳入值 | |
function M:runWithSameArgs( ... ) | |
local params = arg or {} | |
local result = {} | |
for i=1, #self._pool do | |
result = { self._pool[i](unpack( params )) } | |
end | |
-- only return last function's result | |
return unpack(result) | |
end | |
function M:clear() | |
for i=#self._pool,1,-1 do | |
self._pool[i] = nil | |
end | |
end | |
function M.new() | |
local obj = {} | |
setmetatable( obj, M_mt ) | |
obj._pool = {} | |
return obj | |
end | |
return M |
Comments
Post a Comment