(apologies for the long post, but i hope to illustrate some points)
My aim is to create garbage-free Delegate Manager with support for any number of delegate signatures/types.
These forums helped me a lot in making that happen. Basically im using a list for delegates, which only register other single-callback delegates, to avoid garbage. Im also using an ObjectPool to pre-allocate the delegate instances, so that there is no garbage when adding/removing/invoking delegates during runtime.
The problem i have, is when i try to automatically handle different delegate types. I tried generics, but the delegate must be strongly typed during declaration, also there is no base class for a delegate. And then there is an issue of Invoking a delegate using generics.
From what i can see (and i hope to be wrong), there are only 2 ways to handle the storage(structure)/addition/removal/invocation of managed delegates, that would be garbage free. There are drawbacks to each of these and i hope someone can offer alternative or suggest some C# magic.
[i will now post simplified version of structure, to illustrate these points]
Option1: āstore by typeā, as an object.
With a Dictionary<Type, List>, i can store by delegate Type, and store the instance as an object. This messes up OOP which i dont like, but could live with here, if it could automatize the management of different delegate types. Storage and removal thus works for any delegate type. Execution is a problem.
Example (Execution):
// invoke registrees of specific type (note this is minimal code sample, and doesnt make sense on its own. Just focus on the responsibility, which is Invocation of a delegate type.)
public void InvokeListeners<T>()
{
Type registreeType = typeof(T);
List<object> registrees = registreeDelegates[registreeType];
for (int i=registrees.Count-1; i>=0; i--) {
//registrees[i](); // cant invoke an object. how to tell it its a delegate of its Type?
//((VoidVoidDelegate)registrees[i])(); // works, but assumes a Type.
//((T)registrees[i])(); // in case of generic function, we cant assume T is invokable
ExecuteAsDelegate (registrees[i], registreeType); // switch/case works, but breaks automatization
}
}
private void ExecuteAsDelegate (object registree, Type registreeType)
{
// how to automatize this, not have to call by specific type
// afaik there is no way to Invoke a generic delegate (cast as object),
// while knowing only its System.Type?
if (registreeType == typeof(VoidVoidDelegate)) {
((VoidVoidDelegate)registree)();
}
// else .. for remaining delegate Types
}
Option2: Using overloaded functions, when adding different delegate Types.
Good OOP, bad for management (adding almost duplicate code, every time we add new delegate signature).
Structure changes. Instead of Dictionary<Type, List>, we use separate variables for typed Lists (also bad for management).
Example (Add Listener):
public void AddListener(VoidVoidDelegate registree)
{
if (!registreesVoidVoid.Contains(registree)) {
registreesVoidVoid.Add (registree);
}
}
public void AddListener(StringVoidDelegate registree)
{
if (!registreesStringVoid.Contains(registree)) {
registreesStringVoid.Add (registree);
}
}
public
TL;DR:
Option1: bad for OOP, provides automatization, except for Invocation, which i dont know how to automatize.
Option2: good for OOP, separate variables for list of each delegate type, extra functions per each type = bloated code.
Option3: Your suggestions/ammends for a better approach than Option1/2. Requirements are 1) full automatization (just call by type and manager handles the rest) and 2) garbage-free. OOP-friendly (no āobjectā) is nice but not required for this sealed class.