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

时间:2018-10-04 15:00:46

标签: c# generics generic-programming

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

在我的程序中,我订阅了一些事件,这些事件将方法链接到某些事件类型-当事件发布时,我希望该方法执行。当使用真实的东西时,这很不错。

但是,它确实使我的测试依赖于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);
  }
}

2 个答案:

答案 0 :(得分:0)

我坚决反对在任何代码中丢失强类型,我认为您不应尝试通过创建“任何内容”列表来解决问题。

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

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)。

答案 1 :(得分:0)

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

您可以说丢失的那张是

var dynamicInvoke = d1.DynamicInvoke(o)

我也有一个“真实的”前端,可以将调用中继到实际运行的应用程序的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()
    {

    }
}