Problem
ScriptInvoker is used for event callbacks, but it has two problems:
- It doesn't call inserted callback if invoke called before insertion:
MyInvokerClass myInvoker; myInvoker.GetOnData().Insert(fn1); // fn1 is called myInvoker.OnData(new MyData()); myInvoker.GetOnData().Insert(fn2); // but fn2 is not called // to call fn2 you need to add extra code everywehere if (/* some condition */) fn2();
- Manually calling inserted callback can be difficult due to mandatory function parameters that you don't have access to and/or can be difficult to get:
MyData data = myInvoker.GetData(); // GetData may be missing or non-public if (data) // GetData fn2(data); // or array<MyData> dataArr = new array<MyData>(); myInvoker.GetDataArray(dataArr); // GetDataArray can be very expensive due to creating a copy of the array, while myInvoker has direct access to it and calls the inserted callback by passing it directly. foreach (MyData data : dataArr) { fn2(data); };
Solution
To solve these problems I suggest to add PersistentScriptInvokerBase class with definition like this:
class PersistentScriptInvokerBase<Class T> : ScriptInvokerBase<T> { protected func m_PersistentCallback; void PersistentScriptInvokerBase(func fn) { SetPersistentCallback(fn); }; void SetPersistentCallback(func fn) { m_PersistentCallback = fn; }; func GetPersistentCallback() { return m_PersistentCallback; }; override void Insert(T fn, bool persistent = true) { super.Insert(fn); if (!persistent || !m_PersistentCallback) return; m_PersistentCallback(fn); }; };
Usage example
So, usage will be:
class MyInvokerClass { protected MyData m_Data; protected PersistentScriptInvoker m_OnDataEvent; void MyInvokerClass() { m_Data = null; m_OnDataEvent = PersistentScriptInvoker(OnPersistentStateChanged); }; void OnData(MyData data) { m_Data = data; if (!data) return; m_OnDataEvent.Invoke(this, data); }; void OnPersistentData(func fn) { if (!m_Data) return; fn(this, m_Data) }; PersistentScriptInvoker GetOnData() { return m_OnDataEvent; }; };
MyInvokerClass myInvoker; myInvoker.GetOnData().Insert(fn1); // fn1 is not called myInvoker.OnData(new MyData()); // fn1 is called myInvoker.GetOnData().Insert(fn2); // fn2 is called myInvoker.GetOnData().Insert(fn3, false); // fn3 is not called myInvoker.GetOnData().Insert(fn4, persistent); // fn4 is called if persistent is true myInvoker.OnData(new MyData()); // fn1, fn2, fn3 and fn4 are called