Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Func with Task in C#

Tags:

c#

delegates

I'm having some problems trying to understand how exactly Func works in C#, despite having read a handful og good blogposts about it.

I have the following scenario: I'm building a small billing system which uses the Azure Service Bus queue to process billings. There's two processes that can be initialized by the user:

  1. Create a daybook for checking that the transactions are correct before
  2. creating the actual invoice for the customer

For this, I've made a general method which initializes a billing task (containing N billings) which takes a bool parameter to tell if it's a daybook or actual billings that needs to be created. Inside this method, I'm running the following check:

if (isDayBookProcessing)
{
    // Daybook processing code here   
}
else
{
    // Run queue process async
    StartQueueProcess(queueName, billingTaskId, numOfItemsEnqueued);
}

I've then got a general "StartQueueProcess" method, which is run in it's own Task like this:

private void StartQueueProcess(string queueName, int billingTaskId, int numOfItemsEnqueued)
{
    Task.Factory.StartNew(() => _factory.AzureFactory.ServiceBus.ProcessBillingQueue(queueName, billingTaskId, numOfItemsEnqueued));
}

As you can see, the StartQueueProcess method runs the ProcessBillingQueue method on m y ServiceBusclass, which means that it can't run a ProcessDaybookQueue

What I initially thought was to just make use of Func<string, int, int, bool> and make StartQueueProcessmethod return a bool (since Func needs to return something) making it look like this:

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;
}

However, this gives an error telling me that Argument type 'void' is not assignable to parameter type 'System.Func<string, int, int bool>'

My _factory.AzureFactory.ServiceBus.ProcessDaybookQueue(queueName, billingTaskId, numOfItemsEnqueued) returns void. Making it return Func<string, int, int, bool> gives no errors. But why exactly? Shouldn't I be able to make it return what I want (i.e. void)?

Can anyone shed some light on this? :-)

like image 569
Bo Mortensen Avatar asked Aug 22 '26 19:08

Bo Mortensen


1 Answers

You don't need a Func, you need an Action. A Func is when your delegate has a return value. An Action is fit when there is no return value:

private void StartQueueProcess(Action<string, int, int> processMethod)
{
    Task.Factory.StartNew(() => processMethod);
}

Note, that wrapping async over sync is an anti-pattern. You're better off using Task.Run at the call-site instead:

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));
} 

Although I see you're invoking the same method, so I don't see the need for an if-else.

like image 112
Yuval Itzchakov Avatar answered Aug 24 '26 09:08

Yuval Itzchakov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!