如何将通用函数添加到列表并执行它们?

How can I add generic Funcs to a list and execute them?

我正在尝试为我的队列创建一个抽象层以启用更好的集成测试。真正的队列是通过EasyNetQ的RabbitMq。

在我的程序中,我订阅了事件,我通过这些事件对某些事件类型 link 方法——当事件发布时,我希望执行该方法。当使用真实的东西时,这显然很有效。

然而,它确实使我的测试依赖于 RabbitMq 服务器,并且它确实使代码执行异步,一方面,这使得很难确定何时应将测试视为完成。

我不想用这个问题来讨论在我的测试中抽象出 RabbitMq 的决定。

要创建一个存根以在我的测试中使用,我需要存储对事件处理程序的引用——并且我需要在随后发布相关类型的事件时执行事件处理程序。

所以我想我需要像下面写的那样的代码。我可以将事件处理程序存储为委托,但如何调用它们? RabbitMq 事件处理程序采用 Func 形式,其中 T 是处理程序处理的事件类型。

Func<int, Task> handle1 = ...;
Func<string, Task> handle2 = ...;

List<> l = new List<>();
l.Add( handle1);
l.Add( handle2);

foreach(Func f in l)
{
  if (f-parameter is string)
  {
    f("");
  }
  if (f-parameter is int)
  {
    f(1);
  }
}

我是任何代码中失去强类型的死敌,在我看来你不应该试图通过创建 "anything".

列表来解决你的问题

另一方面,我不知道你的代码,如果这是唯一的方法,你可以试试这个方法:

Func<int,    Task> f1 = i => Task.FromResult(i);
Func<string, Task> f2 = s => Task.FromResult(s);

var list = new List<object>
{
    f1,
    f2
};

foreach(var anything in list)
    switch(anything)
    {
        case Func<int,    Task> intFunction: intFunction(1); break;
        case Func<string, Task> strFunction: strFunction("text"); break;
        default: throw new ArgumentException($"I'm not prepared to deal with {anything} function prototype.");
    }

此代码使用了 C# 7 中的一些重要功能,即模式匹配(切换对象类型)和内联变量 (int/strFunction)。

我最终得到了以下解决方案。它允许我完全伪造我对 RabbitMq 的使用,并根据需要为每个发布的消息激活事件处理程序。此外,它没有特定的事件名称 类,允许我将它重新用于我对 RabbitMq 解决方案的所有集成测试。

你可以说丢失的部分是

var dynamicInvoke = d1.DynamicInvoke(o)

我也有一个 'real' 前端,为实际的 运行 应用程序中继对 RabbitMq / EasyNetQ 的调用。

感谢您的参与,@ensisNoctis!

  public class TestBusFront : IBusFront
  {
    private readonly Dictionary<string, List<Delegate>> _list;

    public TestBusFront()
    {
        _list=new Dictionary<string, List<Delegate>>();
    }
    public void Publish(object o)
    {
        var d = GetDelegateListForEvent(o.GetType().FullName);
        foreach (var d1 in d)
        {
            var dynamicInvoke = d1.DynamicInvoke(o);
            var task = (Task) dynamicInvoke;
            task.Wait();
        }
    }

    public void SubscribeAsync<T>(string s, Func<T, Task> handle)
    {
        var delegates = GetDelegateListForEvent(typeof(T).FullName);
        delegates.Add(handle);
    }

    private List<Delegate> GetDelegateListForEvent(string eventName)
    {
        if(!_list.ContainsKey(eventName))
            _list.Add(eventName,new List<Delegate>());

        return _list[eventName];
    }

    public void Dispose()
    {

    }
}