## Problem
`ScriptInvoker` is used for event callbacks, but it has two problems:
1. It doesn't call inserted callback if invoke called before insertion:
```
lang=cs
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();
```
2. 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:
```
lang=cs
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:
```cs
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:
```
lang=cs
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;
};
};
```
```
lang=cs
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
```