在 C# 中使用 Func 和 Task
本文关键字:Func Task | 更新日期: 2023-09-27 18:00:33
尽管我已经阅读了一些关于它的好博客文章,但我在试图理解Func
在 C# 中究竟是如何工作的时遇到了一些问题。
我有以下情况:我正在构建一个小型计费系统,该系统使用 Azure 服务总线队列来处理计费。用户可以初始化两个进程:
- 创建日记簿以检查交易是否正确
- 为客户创建实际发票
为此,我制作了一个通用方法,用于初始化计费任务(包含 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 y ServiceBus
类上运行 ProcessBillingQueue
方法,这意味着它无法运行ProcessDaybookQueue
我最初的想法是只利用Func<string, int, int, bool>
并使StartQueueProcess
方法返回一个布尔值(因为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>
不会出错。但究竟是为什么呢?我不应该让它返回我想要的(即无效(吗?
谁能对此有所了解? :-(
你不需要Func
,你需要一个Action
。Func
是指委托具有返回值。当没有返回值时,Action
适合:
private void StartQueueProcess(Action<string, int, int> processMethod)
{
Task.Factory.StartNew(() => processMethod);
}
请注意,通过同步包装异步是一种反模式。您最好在呼叫站点使用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.我担心Task.Factory.StartNew(() => processMethod)
不会做你期望它做的事情。它不会执行processMethod
.2. StartQueueProcess
被定义为接受具有三个参数的 Func<> 函数。它没有说明参数本身。您有责任为此 lambda 提供一些参数。
你为什么假设你需要在这里使用Func<>
?你不必这样做。您的StartQueueProcess
可以像这样:
private bool StartQueueProcess(
string param1,
int param2,
int param3,
Action<string, int, int> processMethod)
{
Task.Factory.StartNew(() => processMethod(param1, param2, param3));
}
例如,这个 StartNew 重载将很乐意接受任何操作参数(。
此外,在这种特殊情况下,我认为根本不需要声明一个新函数。一个简单的.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));
}