c# - How to dynamically invoke delegates with known parameter base type? -
i trying implement own messaging system unity game. have basic version working - simplified example of follows:
// messaging class: private dictionary<type, list<func<message, bool>>> listeners; // set other code. public void addlistener<t>(func<message, bool> listener) t : message { this.listeners[typeof(t)].add(listener); } public void sendmessage<t>(t message) t : message { foreach (func<message, bool> listener in this.listeners[typeof(t)]) { listener(message); } } // other class: private void start() { messaging.addlistener<mymessage>(this.messagehandler); // subscribe messages of type. } private bool messagehandler(message message) { // receive message message base type... mymessage message2 = (mymessage)message; // ...so have cast mymessage. // handle message. }
this works fine. implement "magic" allow message handler called actual derived type, this:
private bool messagehandler(mymessage message) { // handle message. }
this mean message handling code across thousands of scripts not need bother casting message object correct derived type - of type. far more convenient. feel possible achieve somehow using generics, delegates, expression trees, covariance and/or contravariance, i'm not getting it!
i've been trying lot of different things, , feel getting close, can't there. these 2 partial solutions i've been able come with:
// messaging class: private dictionary<type, list<delegate>> listeners; // delegate instead of func<message, bool>. public void addlistener<t>(func<t, bool> listener) t : message { // func<t, bool> instead of func<message, bool>. this.listeners[typeof(t)].add(listener); } public void sendmessage<t>(t message) t : message { foreach (delegate listener in this.listeners[typeof(t)]) { listener.method.invoke(method.target, new object[] { message }); // partial solution 1. ((func<t, bool>)listener)(message); // partial solution 2. } }
partial solution 1 works fine, uses reflection, isn't option considering performance - game, , messaging system used lot. partial solution 2 works, long t generic parameter available. messaging system have queue of message objects process, , t not available there.
is there way achieve this? appreciate offer!
one final thing note using unity, uses mono - .net 4 not option, , far know rules out using "dynamic".
if understood question correctly, want have common way of storing , invoking message handlers while providing specific message type each handler.
one way use base-typed inteface handler , generic-typed implementation:
interface imessagehandler { bool processmessage(message m); } class messagehandler<t>: imessagehandler t:message { func<t, bool> handlerdelegate; public messagehandler(func<t, bool> handlerdelegate) { this.handlerdelegate = handlerdelegate; } public bool processmessage(message m) { handlerdelegate((t)m); } }
your handler dictionary should hold imessagehandler value, , in addlistener method create messagehandler , add handler dictionary. this:
private dictionary<type, imessagehandler> listeners; public void addlistener<t>(func<t, bool> listener) t : message { this.listeners[typeof(t)].add(new messagehandler<t>(listener)); } public void sendmessage(message message) { foreach (imessagehandler listener in this.listeners[message.gettype()]) { listener.processmessage(message); } }
that way can call sendmessage without generic parameter , typed argument in actual handler method.
Comments
Post a Comment