我在尝试理解Func
在C#中的确切运作方式时遇到了一些问题,尽管我已经阅读了一些关于它的好博客文章。
我有以下情况: 我正在构建一个小型计费系统,它使用Azure Service Bus队列来处理账单。用户可以初始化两个进程:
为此,我提出了一种初始化计费任务(包含N个账单)的通用方法,该方法采用bool
参数来判断是否需要创建日记本或实际账单。在这个方法中,我正在运行以下检查:
if (isDayBookProcessing)
{
// Daybook processing code here
}
else
{
// Run queue process async
StartQueueProcess(queueName, billingTaskId, numOfItemsEnqueued);
}
然后我得到了一个通用的“StartQueueProcess”方法,该方法在它自己的Task
中运行,如下所示:
private void StartQueueProcess(string queueName, int billingTaskId, int numOfItemsEnqueued)
{
Task.Factory.StartNew(() => _factory.AzureFactory.ServiceBus.ProcessBillingQueue(queueName, billingTaskId, numOfItemsEnqueued));
}
如您所见,StartQueueProcess
方法在m ProcessBillingQueue
类上运行ServiceBus
方法,这意味着它无法运行ProcessDaybookQueue
我最初的想法是只使用Func<string, int, int, bool>
并使StartQueueProcess
方法返回一个bool(因为Func
需要返回一些东西),使它看起来像这样:
if (isDayBookProcessing)
{
// Daybook processing code here
StartQueueProcess(_factory.AzureFactory.ServiceBus.ProcessDaybookQueue(queueName, billingTaskId, numOfItemsEnqueued));
}
else
{
// Run queue process async
StartQueueProcess(_factory.AzureFactory.ServiceBus.ProcessBillingQueue(queueName, billingTaskId, numOfItemsEnqueued));
}
private bool StartQueueProcess(Func<string, int, int, bool> processMethod)
{
Task.Factory.StartNew(() => processMethod);
return true;
}
然而,这给我一个错误,告诉我Argument type 'void' is not assignable to parameter type 'System.Func<string, int, int bool>'
我的_factory.AzureFactory.ServiceBus.ProcessDaybookQueue(queueName, billingTaskId, numOfItemsEnqueued)
返回无效。让它返回Func<string, int, int, bool>
没有错误。但为什么呢?我不应该能够让它返回我想要的东西(即无效)吗?
有人可以对此有所了解吗? : - )
答案 0 :(得分:2)
您不需要Func
,需要Action
。 Func
是您的委托具有返回值的时间。当没有返回值时,Action
是合适的:
private void StartQueueProcess(Action<string, int, int> processMethod)
{
Task.Factory.StartNew(() => processMethod);
}
注意,包裹async over sync is an anti-pattern。您最好在呼叫站点使用Task.Run
:
if (isDayBookProcessing)
{
// Daybook processing code here
Task.Run(() => _factory.AzureFactory.ServiceBus.ProcessDaybookQueue(
queueName,
billingTaskId,
numOfItemsEnqueued));
}
else
{
// Run queue process async
Task.Run(() => _factory.AzureFactory.ServiceBus.ProcessBillingQueue(
queueName,
billingTaskId,
numOfItemsEnqueued));
}
虽然我看到您正在调用相同的方法,但我认为不需要if-else
。
答案 1 :(得分:0)
我看到两个不同的问题:
我担心Task.Factory.StartNew(() => processMethod)
不会做你期望它做的事情。它不会执行processMethod
。
2. StartQueueProcess
被定义为接受Func&lt;&gt;功能有三个参数。它没有提到参数本身。你有责任为这个lambda提供一些参数。
为什么你假设你需要在这里使用Func<>
?你不必。您的StartQueueProcess
可以这样:
private bool StartQueueProcess(
string param1,
int param2,
int param3,
Action<string, int, int> processMethod)
{
Task.Factory.StartNew(() => processMethod(param1, param2, param3));
}
E.g。这个StartNew重载将很乐意接受任何Action参数。)
此外,在这种特殊情况下,我认为根本不需要声明新功能。一个简单的.StartNew
调用可能会很好(尽管它很接近):
if (isDayBookProcessing)
{
// Daybook processing code here
Task.Factory.StartNew(() => _factory
.AzureFactory
.ServiceBus
.ProcessDaybookQueue(queueName, billingTaskId, numOfItemsEnqueued));
}
else
{
// Run queue process async
Task.Factory.StartNew(() => _factory
.AzureFactory
.ServiceBus
.ProcessBillingQueue(queueName, billingTaskId, numOfItemsEnqueued));
}