如何将通用函数添加到列表并执行它们?
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()
{
}
}
我正在尝试为我的队列创建一个抽象层以启用更好的集成测试。真正的队列是通过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()
{
}
}