Home > Software design >  Storing a generic Action in a Dictionary
Storing a generic Action in a Dictionary

Time:02-02

T is fine for the method but doesn't work for the Dictionary without defining T on the class which I can't do. Is this possible? If not, is there another way to accomplish storing generic callback methods like this.

This class is for a Websockets Json-Rpc client. The API I'm connecting to allows you to subscribe to different data streams. I.e. stock quotes, stock trades, etc which all have different fields.

I'd like to be able to pass in the name of the data to subscribe to, then a callback, and it's param type, which will pass in the data once it's returned.

// Store list of callback to invoke once data arrives
private Dictionary<string, Action<T>> _callbacks = new Dictionary<string, Action<T>>();

// Subscribe to websocket API streaming data
public async Task SubscribeAsync<T>(string name, Action<T> callback)
{
    _callbacks.Add(name, callback);

    ... other code here ...

}

// Data is eventually received here from the websocket API
private async Task _wsClient_OnDataReceived(string jsonData)
{
    var docRoot = JsonDocument.Parse(jsonData).RootElement;
    var deserialzizedData = ...
    _callbacks[dataName].Invoke(deserialzizedData);
}

CodePudding user response:

This works. Note that SubscribeAsync<T> became SubscribeAsync as type is passed in 2nd parameter:

namespace Callbacks {
    class SubMgr<T> {
        private Dictionary<string, Action<T>> _callbacks = new Dictionary<string, Action<T>>();

        public async Task SubscribeAsync(string name, Action<T> callback ) {

            _callbacks.Add(name, callback);
            _callbacks.Add(name, Method1);
            _callbacks.Add(name, Method2);

            // ... other code here...
        }

        public void Method1(T a) { }
        public void Method2(T a) { }

    }
}

CodePudding user response:

The problem is that you are trying to store multiple potentially polymorphic types in a Dictionary<TKey, TValue>. However, the dictionary expects that every item in it will have exactly the same type. So, in your case, every Action<T> must be exactly the same, meaning that <T> must be the same type for all instances.

You can get around this, however, if is an interface. For example:

private Dictionary<string, Action<IActionable>> _callbacks = new Dictionary<string, Action<IActionable>>();

where IActionable is some common interface that all the types implement. Or, instead of an interface, it's a common base class that they all inherit from.

In any event, the point is that you want Action<T> to be the same, but treat the instances polymorphically. To do so, you need either an interface that they implement or a common base class with the method you want to invoke. You'll add items to the dictionary as instances of either the interface or base class, and you'll invoke the desired method through the same.

  •  Tags:  
  • Related