在 C# 中使用 Func 和 Task

本文关键字:Func Task | 更新日期: 2023-09-27 18:00:33

尽管我已经阅读了一些关于它的好博客文章,但我在试图理解Func在 C# 中究竟是如何工作的时遇到了一些问题。

我有以下情况:我正在构建一个小型计费系统,该系统使用 Azure 服务总线队列来处理计费。用户可以初始化两个进程:

  1. 创建日记簿以检查交易是否正确
  2. 为客户创建实际发票

为此,我制作了一个通用方法,用于初始化计费任务(包含 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>不会出错。但究竟是为什么呢?我不应该让它返回我想要的(即无效(吗?

谁能对此有所了解? :-(

在 C# 中使用 Func 和 Task

你不需要Func,你需要一个ActionFunc是指委托具有返回值。当没有返回值时,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));
}