(I really tried to come up with a better title, feel free to edit)
Suppose I have a generic event handler interface and implementations:
public interface IEventHandler<T>
{
void HandleEvent(T t);
}
public class SlowButAccurateEventHandler<T> : IEventHandler<T>
{
// To emphasize that the implementation depends on T
private void SomeHelperClass<T> helperClass;
public void HandleEvent(T t) { ... }
}
public class FastEventHandler<T> : IEventHandler<T>
{
// To emphasize that the implementation depends on T
private void SomeHelperClass<T> helperClass;
public void HandleEvent(T t) { ... }
}
and another class which I'd like to hold instances of EventHandlers, but cannot have generic methods since it's a WCF service:
public class MyService : MyContract
{
// Pseudo (doesn't compile)
private Dictionary<Type, IEventHandler<T>> eventHandlers;
public MyService()
{
// More pseudo...
eventHandlers = new Dictionary<Type, IEventHandler<T>>()
{
{ typeof(string), new SlowButAccurateEventHandler<string>() },
{ typeof(int), new FastEventHandler<int>() },
};
}
public void RouteToEventHandler(object userEvent)
{
var handler = eventHandlers[typeof(userEvent))];
handler.HandleEvent(userEvent); // I realize that userEvent needs to be converted here
}
}
So basically, I have some service ( MyService
) that I'd like to hold IEventHandlers
and dispatch the correct handler when some event arrives. To do that, I'd like to keep a dictionary that holds a mapping between the CLR type and the suitable IEventHandler. Is that possible?
You should define your interface like this:
public interface IEventHandler<T>
{
void HandleEvent(object t);
}
And then in the implementation:
public class FastEventHandler<T> : IEventHandler<T>
{
// To emphasize that the implementation depends on T
private void SomeHelperClass<T> helperClass;
public void HandleEvent(object t)
{
if (t == null || !Type.Equals(t.GetType(), typeof(T)))
{
// We cannot handle the event.
return;
}
T typedValue = Convert(t);
// Here comes the rest of handling process.
}
private T Convert(object value)
{
try
{
return (T)value;
}
catch
{
return default(T);
}
}
}
Another implementation, however I would stay at my previous answer:
public interface IEventHandler
{
void HandleEvent(object value);
}
public interface IEventHandler<T> : IEventHandler
{
void HandleEvent(T value);
}
public abstract class EventHandler<T> : IEventHandler<T>
{
public void HandleEvent(object value)
{
if (value == null || !Type.Equals(value.GetType(), typeof(T)))
{
return;
}
HandleEvent(Convert(value));
}
private T Convert(object value)
{
try
{
return (T)value;
}
catch
{
return default(T);
}
}
public abstract void HandleEvent(T value);
}
public class FastEventHandler<T> : EventHandler<T>
{
public override void HandleEvent(T value)
{
throw new NotImplementedException();
}
}
In the constructor you can initialize the event handlers:
var handlers = new Dictionary<Type, IEventHandler>()
{
{ typeof(string), new FastEventHandler<string>() },
{ typeof(int), new FastEventHandler<int>() }
};
Then:
public void RouteToEventHandler(object userEvent)
{
if (userEvent == null)
{
return;
}
var handler = handlers[userEvent.GetType()];
handler.HandleEvent(userEvent);
}
One way of course would be to store the handlers inside Dictionary<Type, object>
and then use reflection to call the method in interest. In case you are interested in single method (like in your example), you can build and store a delegate call to that method instead, like this:
public class MyService : MyContract
{
private Dictionary<Type, Action<object>> eventHandlers;
static Action<object> GetHandler<T>(IEventHandler<T> handler)
{
var parameter = Expression.Parameter(typeof(object), "t");
var body = Expression.Call(
Expression.Constant(handler),
"HandleEvent", null,
Expression.Convert(parameter, typeof(T)));
return Expression.Lambda<Action<object>>(body, parameter).Compile();
}
public MyService()
{
eventHandlers = new Dictionary<Type, Action<object>>()
{
{ typeof(string), GetHandler(new SlowButAccurateEventHandler<string>()) },
{ typeof(int), GetHandler(new FastEventHandler<int>()) },
};
}
public void RouteToEventHandler(object userEvent)
{
Action<object> handler;
if (eventHandlers.TryGetValue(userEvent.GetType(), out handler))
handler(userEvent);
}
}
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.