'Are there alternate ways to input a parameter into a task besides using lambda functions?

Are there alternate ways to input a parameter(s) into a task besides using lambda functions?

It seems like Task.Run(DoSomethingElse(myInput)); should work since Task.Run(DoSomething); works but clearly it does not.

Using a lambda function only to convert a function with parameters to one without parameters seems odd, like an awkward cast. Task.Run(() => DoSomethingElse(myInput));

Main()
{
    object myInput = new();

    Task.Run(DoSomething); // Happy Code
    Task.Run(() => DoSomethingElse(myInput)); // Happy Code 
    Task.Run(DoSomethingElse(myInput)); // CS1503 Argument 1: cannot convert from 'System.Threading.Tasks.Task' to 'SystemAction'
}

Task DoSomething()
{
    // Something
}

Task DoSomethingElse(object input)
{
    // Something else
}


Solution 1:[1]

Looking at the documentation for Task.Run, you'll notice that every definition takes either a Func<Task> or a Func<Result> or some combination therein. However, none of these definitions include a mention of parameters. Plus, what you're sending when you call Task.Run(DoSomethingElse(myInput)) is the result of calling DoSomethingElse(myInput) because this represents a call to the method itself rather than sending the method and its arguments as a parameter. In effect, that's what using a Lambda does. If you really don't want to insert a lambda into your code you could try adding a static method like this:

public static Task Run<TItem>(f Func<TItem, Task>, i TItem) {
     return Task.Run(() => f(i));
}

Solution 2:[2]

The Task.Run method is basically a shortcut for the Task.Factory.StartNew method, with some default parameters. This is explained in this article by Stephen Toub: Task.Run vs Task.Factory.StartNew.

The Task.Factory.StartNew has also an overload with an object state parameter. You could use this overload for your own set of Task.Run-like shortcuts. You would need four of those, to cover all cases with-or-without-result and with-or-without-async-delegate:

static Task Run(Action<object> action, object state)
{
    return Task.Factory.StartNew(action, state, default,
        TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
}
static Task Run(Func<object, Task> action, object state)
{
    return Task.Factory.StartNew(action, state, default,
        TaskCreationOptions.DenyChildAttach, TaskScheduler.Default).Unwrap();
}
static Task<TResult> Run<TResult>(Func<object, TResult> action, object state)
{
    return Task.Factory.StartNew(action, state, default,
        TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
}
static Task<TResult> Run<TResult>(Func<object, Task<TResult>> action, object state)
{
    return Task.Factory.StartNew(action, state, default,
        TaskCreationOptions.DenyChildAttach, TaskScheduler.Default).Unwrap();
}

Usage example:

Task task = Run(DoSomethingElse, myInput);

The advantage of this approach is that the myInput is not captured in a closure, as it does when you use a lambda, so your program allocates less memory in the heap. It's an optimization with minuscule, and in most cases negligible, impact.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Theodor Zoulias