简体   繁体   中英

Wildcard generics with callbacks of any type?

I have the following Structs which hold an Action and a T paramater:

public struct CallbackInfo<T>
{
    public readonly Action<T> callback;
    public readonly T param;
}

What i am trying to do is store a list of these callbackInfo structs to of course, callback at some point in time.

Lets say that I store these structs as follows:

public class CallbacksSystem<T> 
{
   List<CallbackInfo<T>> callbacks;

   public void AddCallback<T>(T callback)
   {
       callbacks.Add(callback);
   }

   public void RunCallbacks()
   {
      foreach(CallbackInfo<T> info in callbacks) info.callback(info.param);
   }
}

However, this would mean that I would need to have a new CallbackSystem for each different T i need to submit callbacks for.

Is there a way in c# to have the list stored as a wildcard and get the concrete type at runtime to run the callback Action?

As other have alluded to, your problem may be resolved with Events

If events are not solving your entire problem, I'm sorry to report that wildcard generics do not exist in this case. However, perhaps a lambda-driven approach would suffice.

Proposal 1

Here, the code binds your state and your callback together by capturing them in a lambda. This lambda is then saved in the list like an anonymous function.

public class CallbacksSystem 
{
   private List<Action> Callbacks { get; } = new List<Action>();

   public void AddCallback<T>(Action<T> callback, T parameter) // Or with your struct
   {
       Callbacks.Add(() => callback(parameter));
   }

   public void RunCallbacks()
   {
      foreach(var callback in Callbacks) callback();
   }
}

Proposal 2

If you have multiple instances of this pattern where you locally have a single function which needs to be called multiple times with accumulated parameters, you could instead create a class like this:

public class DeferredCallback<T> 
{
   public DeferredCallback(Action<T> callback)
   {
      Callback = callback;
   }

   private Action<T> Callback { get; }
   private List<T> Parameters { get; } = new List<T>();

   public void AddDeferredCall(T parameter)
   {
      Parameters.Add(parameter);
   }

   public void RunCallbacks()
   {
      foreach(var parameter in Parameters) Callback(parameter);
   }
}

You would then instantiate this class once for each callback you have. What fits best would all depend on how the rest of the problem (and the system) looks like, but these examples will hopefully put you on the right path(?).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM