【问题标题】:Using type array for "batch"-calling of the same generic method with different generic parameters使用类型数组“批量”调用具有不同泛型参数的相同泛型方法
【发布时间】:2014-12-18 04:24:35
【问题描述】:

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

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

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

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

该方法接受一个 T 并检查给定的 BusMessage 是否实际上是 BusMessage&lt;T&gt;,这意味着它的值是 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) } 的方向可能是什么?

【问题讨论】:

  • 我假设您想避免使用动态类型?你目前有多少地方有这种重复?如果它只是在一个方法中,我可能会保持原样。
  • 在了解并查看了 Illidans4 对问题的解决方案后,我同意你的看法,并保持我的代码原样——即使至少有两个几十个地方被维护,将来也会更容易维护堆满了几乎相同的代码行。

标签: c# generics


【解决方案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);
    }
}

但是,在这种情况下,为了清晰起见,我更喜欢您的原始代码(如果您不想更改其他方法的代码,它可能是最短的代码)。

【讨论】:

  • 解决这个问题的一种有趣的方法,尤其是对我来说,因为我以前从未与表达式有关。然而,由于可读性和更好的理解性,我现在确信要坚持我原来的方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-26
  • 1970-01-01
相关资源
最近更新 更多