How to convert an action to Func <Task> without starting a task?

I have a code that works exactly as desired. However, our corporate build server rejects any registration that has a compiler warning.

The following warning (as expected) displayed for an Action constructor with Action to Func transformations, since I am not using a wait statement.

In this asynchronous method, there are no โ€œwaitโ€ statements and will be executed synchronously. Think about how to use the โ€œwaitโ€ operator to wait for non-blocking API calls or โ€œwait for Task.Run (...)โ€ to do the work of binding to the processor in the background thread.

 public class TransactionOperation { private readonly Func<Task> _operation; private readonly Func<Task> _rollback; public OperationStatus Status { get; private set; } public TransactionOperation(Func<Task> operation, Func<Task> rollback) { _operation = operation; _rollback = rollback; Status = OperationStatus.NotStarted; } public TransactionOperation(Action operation, Action rollback) { _operation = async () => operation.Invoke(); _rollback = async () => rollback.Invoke(); Status = OperationStatus.NotStarted; } public async Task Invoke() { try { Status = OperationStatus.InProcess; await _operation.Invoke(); Status = OperationStatus.Completed; } catch (Exception ex) { //... } } } 

What is the correct way to rewrite this code so that the action is correctly converted to Func without executing or creating a new thread (i.e. wait for Task.Run ())?


Update - Proposed Answer No. 1

_operation = () => new task (operation .Invoke);

_rollback = () => new task (rollback.Invoke);

I have tried this before. This causes this unit test to never return.

 [TestMethod, TestCategory("Unit Test")] public async Task Transaction_MultiStepTransactionExceptionOnFourthAction_CorrectActionsRolledBack() { var operation = new TransactionOperation(PerformAction, () => RollbackOperation(1)); var operation2 = new TransactionOperation(PerformAction, () => RollbackOperation(2)); var operation3 = new TransactionOperation(PerformAction, () => RollbackOperation(3)); var operation4 = new TransactionOperation(ExceptionAction, () => RollbackOperation(4)); var operation5 = new TransactionOperation(PerformAction, () => RollbackOperation(5)); var transaction = new Transaction(new[] { operation, operation2, operation3, operation4, operation5 }); await IgnoreExceptions(transaction.ExecuteAsync); AssertActionsPerformedThrough(4); AssertActionsRolledBackThrough(4); } 

Refresh - accepted answer

 private async Task ConvertToTask(Action action) { action.Invoke(); await Task.FromResult(true); } 

Here's the updated Action constructor:

 public TransactionOperation(Action operation, Action rollback) { _operation = () => ConvertToTask(operation); _rollback = () => ConvertToTask(rollback); Status = OperationStatus.NotStarted; } 
+7
source share
2 answers

You can simply use Task.FromResult(0) :

 _operation = async () => { operation.Invoke(); await Task.FromResult(0); }; 
+9
source

You mean the following:

 _operation = () => new Task(operation.Invoke); _rollback = () => new Task(rollback.Invoke); 

The functions then return the task with the desired action, which has not yet been started.

I think you will need to update your Invoke method to the following to get the behavior you are looking for:

 Status = OperationStatus.InProcess; await Task.Run(() => { _operation().Start(); _operation().Wait(); }); Status = OperationStatus.Completed; 
+2
source

All Articles