C#-如何将对象映射到适合该对象类型的泛型类



(我真的试着想出一个更好的标题,可以随意编辑)

假设我有一个通用的事件处理程序接口和实现:

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) { ... }
} 

和另一个类,我想保存EventHandlers的实例,但由于它是WCF服务,所以不能具有通用方法:

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
    }
}

因此,基本上,我有一些服务(MyService),我想保存IEventHandlers,并在某个事件到达时调度正确的处理程序。为此,我想保留一个字典,其中包含CLR类型和合适的IEventHandler之间的映射。这可能吗?

另一个实现,但我会停留在以前的答案:

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();
    }
}

在构造函数中,您可以初始化事件处理程序:

var handlers = new Dictionary<Type, IEventHandler>()
{
    { typeof(string), new FastEventHandler<string>() },
    { typeof(int), new FastEventHandler<int>() }
};

然后:

public void RouteToEventHandler(object userEvent)
{
    if (userEvent == null)
    {
        return;
    }
    var handler = handlers[userEvent.GetType()];
    handler.HandleEvent(userEvent);
}

您应该这样定义您的接口:

public interface IEventHandler<T>
{
    void HandleEvent(object t);
}

然后在实现中:

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);
        }
    }
} 

当然,一种方法是将处理程序存储在Dictionary<Type, object>中,然后使用反射来调用感兴趣的方法。如果您对单个方法感兴趣(如您的示例),您可以构建并存储对该方法的委托调用,如下所示:

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);
    }
}

最新更新