Invoke Action with an unknown type parameter (Action <any>)
I am creating an API, and my goal is to expose a method that can be called as follows:
Library.AddCallback<string>(Type.ChatMessage, GotMessage); private void GotMessage(string message) { //... } //or Library.AddCallback<int>(Type.Number, GotNumber); private void GotNumber(int number) { //... } The type <int> , <string> can be any type.
In the library, the method looks something like this:
public void AddCallback<T1>(object type, Action<T1> callback) { //... } The problem is that somehow I want to first save the callback outside the method call (in the list), and then later it can be called.
What I ideally want to do is first pass it to the object so that it can save it to a List<object> , and then return it back to Action<T1> . However, it seems that it is impossible to save T1 in a variable (except for what typeof(T1) does, which prevents me from using it to return it).
An example of what I would like to call it (where I got type and data from the list):
((Action<type>)callback)(data) I'm not sure how data is typed. Assuming this is an object type at the moment, you can decompose the Action<T> into an Action<object> and cast to them:
private List<Action<object>> Callbacks = new List<Action<object>>(); public void AddCallback<T1>(object type, Action<T1> callback) { Callbacks.Add((data) => callback((T1)data)); } public void FireCallback(object data) { Action<object> callback = GetCallback(); callback(data); } EDIT: You already marked it as an answer, but here is another implementation that stores callbacks in a typed set.
A CallbackHandler stores the entered callback list:
public class CallbackHandler<T> : ICallbackHandler { private List<Action<T>> Callbacks = new List<Action<T>>(); public void AddCallback<T>(Action<T> callback) { Callbacks.Add(callback); } public void Callback(object data) { T typedData = (T)data; foreach(var callback in Callbacks) callback(typedData); } } public interface ICallbackHandler { void Callback(object data); } Then your higher level Library has something like this:
private Dictionary<Type, ICallbackHandler> AllCallbacks = new Dictionary<Type, ICallbackHandler>(); public void AddCallback<T>(Action<T> callback) { Type type = typeof(T); ICallbackHandler handler; if (!AllCallbacks.TryGetValue(type, out handler)) { handler = new CallbackHandler<T>(); AllCallbacks[type] = handler; } CallbackHandler<T> typedHandler = (CallbackHandler<T>)handler; typedHandler.AddCallback(callback); } public void FireCallback(object data) { Type type = data.GetType(); ICallbackHandler handler; AllCallbacks.TryGetValue(type, out handler); if (handler != null) handler.Callback(data); } The data type is supposed to determine which callbacks should fire. If you need to overlay another layer (based on Type.ChatMessage or Type.Number ), this should not be too complicated.
You can do something like this:
List<object> callbacks = new List<object>(); public void AddCallback<T1>(object type, Action<T1> callback) { this.callbacks.Add(callback); } public IEnumerable<Action<T>> GetCallbacks<T>() { return this.callbacks.OfType<Action<T>>(); } And use it as follows:
// Sample callbacks static void Foo(int i) { Console.WriteLine("Foo {0}", i); } static void Bar(string s) { Console.WriteLine("Bar {0}", s); } AddCallback(null, (Action<int>)(Foo)); AddCallback(null, (Action<string>)(Bar)); foreach (var callback in GetCallbacks<int>()) { callback(42); // only calls Foo }