I'm trying to repair some code that I cloned from a public repo. It's an async
method that's missing an await
operator:
public async Task<IEnumerable<JsonPatchOperation>> GetRemoveAllRelationsOperations(IBatchMigrationContext batchContext, WorkItem targetWorkItem)
{
return targetWorkItem.Relations?.Select((r, index) => MigrationHelpers.GetRelationRemoveOperation(index));
}
I'm trying this:
public async Task<IEnumerable<JsonPatchOperation>> GetRemoveAllRelationsOperations(IBatchMigrationContext batchContext, WorkItem targetWorkItem)
{
return await Task.Run(o => targetWorkItem.Relations?.Select((r, index) => MigrationHelpers.GetRelationRemoveOperation(index)));
}
...but I'm getting an error in the IDE:
Delegate 'Action' does not take 1 arguments
I found some similar discussions, but unfortunately none of them quite address the lambda syntax:
It appears the precompiler is interpreting the input as an Action
when it should be seeing it as a Func
instead. But I thought that the statement o => ...
could indicate either.
I'm not familiar enough with C# to be able to work this one out. Can someone assist?
How do I tell the precompiler that I want to send a Func
instead of an Action
?
Well, the reason for the compilation error, is that Task.Run
accepts a (non-generic) Action
, which is a delegate that accepts no arguments.
You have tried to call Task.Run
with a lambda accepting an argument o
, so changing to this will remove the error:
Task.Run(() =>
The parentheses ()
denote no arguments within a lambda expression.
Having said that, wrapping a synchronous function in Task.Run
is an anti-pattern.
If your method is completely synchronous, you should ideally expose it as such:
public IEnumerable<JsonPatchOperation> GetRemoveAllRelationsOperations(IBatchMigrationContext batchContext, WorkItem targetWorkItem)
{
return targetWorkItem.Relations?
.Select((r, index) => MigrationHelpers.GetRelationRemoveOperation(index));
}
If you cannot change the signature, for example if you are implementing an interface, then use Task.FromResult
instead:
public Task<IEnumerable<JsonPatchOperation>> GetRemoveAllRelationsOperations(IBatchMigrationContext batchContext, WorkItem targetWorkItem)
{
return Task.FromResult(targetWorkItem.Relations?
.Select((r, index) => MigrationHelpers.GetRelationRemoveOperation(index)));
}
This just wraps the synchronous result in a Task
object, rather than forcing the lambda to run on the threadpool.