使用类型数组进行“批处理” - 使用不同的通用参数调用相同的泛型方法

时间:2014-12-17 08:27:40

标签: c# generics

我正在寻找一些关于以下方面的更简洁的解决方案:在我的消息总线实现中,我有几个组件,当新消息发布到总线时订阅该事件。消息总线传输BusMessage对象(其值为object)。每个组件还实现了处理特定总线消息的功能(派生组件可以覆盖某些消息类型的现有句柄功能),如下所述。对于传入的字符串类型的总线消息:

protected virtual void HandleMessage(BusMessage<string> msg) { ... }

为了将传入的消息分发到特定的句柄函数,我实现了

static bool TryClassify<T>(BusMessage msg, Action<BusMessage<T>> handleFunction)

接受T并检查给定BusMessage的方法是否实际上是BusMessage<T>,意味着它的值是T类型。事件处理程序总是如下:

void HandleMessage(BusMessage msg)
{
  if (BusMessage.TryClassify<string>(msg, HandleMessage)) return;
}

对于我想在组件中处理的每个特定BusMessage类型,我必须重复使用TryClassify的那一行 - 唯一的区别是我指定的类型,因为要使用的特定HandleMessage由编译器确定。我最终得到了一个由

组成的方法体
if (BusMessage.TryClassify<string>(msg, HandleMessage)) return;
if (BusMessage.TryClassify<bool>(msg, HandleMessage)) return;
if (BusMessage.TryClassify<long>(msg, HandleMessage)) return;
if (BusMessage.TryClassify<int>(msg, HandleMessage)) return;
if (BusMessage.TryClassify<DateTime>(msg, HandleMessage)) return;
...

是否有更优雅,更时尚的方式,更少的样板代码来完成我需要的东西?使用类型{ typeof(string), typeof(bool), typeof(long), typeof(int), typeof(DateTime) }数组的方向可能是什么?

1 个答案:

答案 0 :(得分:1)

您可以使用表达式构建此代码:

class BusMessage
{
    private static readonly Func<BusMessage,Delegate,bool> TryClass;

    static BusMessage()
    {
        Type[] classTypes = new Type[]{typeof(int), typeof(string)};

        MethodInfo mi = typeof(BusMessage).GetMethod("TryClassifyInternal", BindingFlags.NonPublic | BindingFlags.Static);

        var p1 = Expression.Parameter(typeof(BusMessage));
        var p2 = Expression.Parameter(typeof(Delegate));
        Expression exp = null;
        foreach(Type t in classTypes)
        {
            MethodInfo mig = mi.MakeGenericMethod(t);
            Expression e = Expression.Call(mig, p1, Expression.Convert(p2, typeof(Action<>).MakeGenericType(typeof(BusMessage<>).MakeGenericType(t))));
            if(exp == null)
            {
                exp = e;
            }else{
                exp = Expression.OrElse(exp, e);
            }
        }

        TryClass = Expression.Lambda<Func<BusMessage,Delegate,bool>>(exp, p1, p2).Compile();
    }

    private static bool TryClassifyInternal<T>(BusMessage msg, Action<BusMessage<T>> handleFunction)
    {
        //former TryClassify code
        return false;
    }

    public static bool TryClassify(BusMessage msg, Delegate handleFunction)
    {
        return TryClass(msg, handleFunction);
    }
}

但是,在这种情况下,我希望您的原始代码清晰明了(如果您不想更改其他方法的代码,那么它可能是最短的。)