In the process of refactoring some legacy code at work and part of it is to convert an instance of List<Action>
to List<Func<Task>>
. Elsewhere in the codebase, there are several instances of something along the lines of this:
entity.Tasks.Add(() =>
{
_service.Process(operation)
}
The above would work fine when the Tasks property was List<Action>
, but gives errors when turned into List<Func<Task>>
with no obvious way to fix it.
I know next to nothing about Func, Task, Action, asynchronous/synchronous programming, particularly in C#. Any help provided is immensely appreciated or even just a referral to information where I could find the information needed to solve this myself.
CodePudding user response:
A quick primer...
List<Action>
says: I'm a list that accepts a method with no input parameters and returns void
when invoked.
List<Func<Task>>
says: I'm a list that accepts a method with no input parameters and returns a Task
when invoked.
Note: I'm using the term "method" to represent a named method, delegate, lambda, etc...
For your case, entity.Tasks
was originally defined as List<Action>
; but is now defined as List<Func<Task>>
.
Given the case where you need to take the legacy methods which return no value (void), you could create a shimming method which returns a task after completing the Action
from the original method.
For Example...
static Task Shim( Action action )
{
action();
return Task.CompletedTask;
}
// the above will wrap a method that does not return a value such as:
static void DoWork( string str )
{
Debug.WriteLine( str );
}
You can now use the Shim
to add to your new collection type. For example...
var list = new List<Func<Task>>();
// add the Shim to the list
list.Add( () => Shim( () => DoWork( "I'm a shim" ) ));
In your use case, it will look something like this:
entity.Tasks.Add(() =>
{
return Shim( () => _service.Process(operation) );
}
// or a bit more shorthanded:
entity.Tasks.Add( () => Shim( () => _service.Process(operation) ));
As pointed out in the comments, the Shim
path is less than ideal since the new version really should be wrapped in a Task
to be more inline with how Tasks and Exceptions get wrapped up.
Here's an example of wrapping the legacy code into the new version without any shims:
entity.Tasks.Add( () => Task.Run( () => _service.Process(operation) ));
CodePudding user response:
Actions are your void methods that don't return a response. Your tasks collection is expecting a returned task. You can wrap the _service.Process(operation) with a task and within the task, run the _service.Process, then return something like
return Task.FromResult(false);