Home > OS >  Is there a way to take a synchronous method that may or may not return a value and add it to a List&
Is there a way to take a synchronous method that may or may not return a value and add it to a List&

Time:11-05

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

  • Related