在 C# 中将 Func 与任务一起使用
Using Func with Task in C#
我在尝试理解 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
方法 运行 是 ServiceBus
class 上的 ProcessBillingQueue
方法,这意味着它不能运行一个ProcessDaybookQueue
我最初的想法是利用 Func<string, int, int, bool>
并使 StartQueueProcess
方法 return 成为布尔值(因为 Func
需要 return 一些东西) 使其看起来像这样:
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)
return无效。使它 return Func<string, int, int, bool>
没有错误。但究竟是为什么?难道我不能 return 我想要的(即 void)吗?
任何人都可以阐明这一点吗? :-)
您不需要 Func
,您需要 Action
。 Func
是指您的代表具有 return 值。当没有 return 值时,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. 恐怕 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 重载将愉快地接受任何 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));
}
我在尝试理解 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
方法 运行 是 ServiceBus
class 上的 ProcessBillingQueue
方法,这意味着它不能运行一个ProcessDaybookQueue
我最初的想法是利用 Func<string, int, int, bool>
并使 StartQueueProcess
方法 return 成为布尔值(因为 Func
需要 return 一些东西) 使其看起来像这样:
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)
return无效。使它 return Func<string, int, int, bool>
没有错误。但究竟是为什么?难道我不能 return 我想要的(即 void)吗?
任何人都可以阐明这一点吗? :-)
您不需要 Func
,您需要 Action
。 Func
是指您的代表具有 return 值。当没有 return 值时,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. 恐怕 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 重载将愉快地接受任何 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));
}