Reputation: 7919
The goal of the following code is to cast any given function into an awaitable function. The idea is to use it when fetching the data from the db, giving the code the flexibility to either use the synchronous fetch functions (an imposition of my current ORM), or use the very same functions as async.
I am aware that there could be many things wrong with the concept behind code. By now I was just trying to get rid of the compiler errors so I can run the code and check the behavior. But of course I am open to discuss the concept beforehand, and if the whole idea behind it is wrong then use my time more efficiently looking for another solution.
async static void Main()
{
// The following line gives a compiler error:
// Error 1 The best overloaded method match for 'CastFuncToTask<int>(System.Func<int>)' has some invalid arguments
int task = await CastFuncToTask<int>(TestFunc(2));
}
private static Task<T> CastFuncToTask<T>(Func<T> func)
{
TaskCompletionSource<T> taskCompletionSource = new TaskCompletionSource<T>();
T result = func.Invoke();
taskCompletionSource.SetResult(result);
return taskCompletionSource.Task;
}
private static int TestFunc(int testInt)
{
return testInt * 2;
}
Upvotes: 21
Views: 27858
Reputation: 47
The problem is that CastFuncToTask runs synchronously. if Func is parameterless you can do something like this:
public static Task<T> ToTask(this Func<T> func) => Task.Factory.StartNew(() => func());
Anyway we can play with TaskCompletionSource and return something we want regardless of the method. Lets say we have Action instead of Func
public static Task<string> ToTask(this Action action)
{ TaskCompletionSource<string> taskCompletionSource = new
TaskCompletionSource<string>();
string result = null;
try
{
Task.Factory.StartNew(() => action());
}
catch (Exception ex)
{
result = ex.Message;
}
taskCompletionSource.SetResult(result);
return taskCompletionSource.Task;
}
Upvotes: -2
Reputation: 19
Below code may help others:
Note: GenericMethod is parameter name which we are passing as Func with Input (T1) and output (T2) of generic Type. Task Factory will provide necessary access to run your task.
public async Task<T2> GenericAsyncCall<T1, T2>(Func<T1, T2> GenericMethod, T1 input)
{
var _output = await Task.Factory.StartNew(() => {
var output = GenericMethod.Invoke(input);
return output;
});
return (T2)_output;
}
Upvotes: 0
Reputation: 149646
Running .NET 4.5, you can greatly simplify your code by doing:
int task = await Task.FromResult(TestFunc(2));
No need to wrap it yourself in a TaskCompletionSource
.
I am aware that there could be many things wrong with the concept behind code.
If what you're trying to do is asynchronously query your database, this solution will definitely not help. It only artificially wraps your result in a Task
. If you really want to query your database asynchronously, you need to use async methods provided by your database provider.
If you're using MySQL and looking for a driver that supports async, look into Dapper
Upvotes: 24
Reputation: 59
my method is this :
public Task<int> SetOffAsync()
{
return Task<int>.Factory.StartNew(() =>
{
/*do something else*/
return 42;
});
}
and you can call this :
int var = await SetOffAsync();
Upvotes: 1
Reputation: 31743
With a windows forms application I confirmed that the first call is blocking the second isn't. So the best solution would be to use Task.Run()
with a lambda expression.
private async void button1_Click(object sender, EventArgs e)
{
button1.Text = "...";
var result = await Task.FromResult(TestFunc(2));
button1.Text = result.ToString();
}
private async void button2_Click(object sender, EventArgs e)
{
button2.Text = "...";
var result = await Task.Run(() => TestFunc(2));
button2.Text = result.ToString();
}
private int TestFunc(int x)
{
System.Threading.Thread.Sleep(5000);
return x;
}
The compiler can not know that you don't want to evaluate TestFunc(2) but use it as a delegate and will just execute the method first and Task.FromResult will just wrap a return value
in a Task. This is not what you want.
Upvotes: 0
Reputation: 6696
change it to
int task = await CastFuncToTask<int>(()=>TestFunc(2));
In your code the input provided for CastFuncToTask
is an int
(what TestFunc
returns.) but it needs a delegate Func<T>
.
Upvotes: 2