Convert any given function into an awaitable task - c#

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

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

You can use:
await Task.Run(() => obj.functionname());

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>.

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

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.

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

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

Related

Get result from Task.Run() function without having to the caller method to wait for it?

Is there a way to get the result of a Task.Run function like this
private Task<bool> UpdteSth(double bla)
=> Task.Run(() =>
{
try
{
UpdateOneAsync(doStuff);
}
catch (Exception exception)
{
sentryClient.CaptureException(exception);
return false;
}
return true;
});
from a caller method like this
public async Task<Entity> Get()
{
UpdateSth(double bla);
}
without having to await UpdateSth so Get can freely do whatever it needs without having to wait to UpdateSth result? I still need to get the result of UpdateSth() to do some logging business but other than that Get should not wait for UpdateSth to be done to continue its job.
Clearly, await and Task.FromResult() still make my Get() to wait for the result or UpdateSth to be done so I cannot used those.
I'm not getting the issue here. If you want to fire-and-forget you just call UpdateSth(bla);. What am I missing here?
Here's an example of what that looks like:
public Task<Entity> Get() =>
Task.Run(() =>
{
double bla = 4.2;
UpdateSth(bla);
return new Entity();
});
This is a trivial example. I feel that there is a more stringent requirement that hasn't been explained in the question.

Awaiting a Callback method

I'm calling a third-party API which has a method that looks like this:
myServiceClient.Discover(key, OnCompletionCallback);
public bool OnCompletionCallback(string response)
{
// my code
}
My challenge is, I have to call Discover because it does some work under-the-covers that I need. At the same time, I have to wait for Discover to complete before running my custom code. To further complicate matters, I can't just put my code in the OnCompletionCallback handler because I need to call the code above from a Func delegate. In short, I want to do this:
Func<SystemTask> myFunction = async () =>
{
await myServiceClient.Discover(key);
// my code
}
However, I can't do this because the third-party API uses a callback approach instead of an async/await approach.
Is there some way to make the callback approach work in an async / await world?
If I understand you correctly you can do something like this
public Task<bool> MyAsyncFunction()
{
var tcs = new TaskCompletionSource<bool>();
myServiceClient.Discover("somekey", s => {
//........
var res = true;
tcs.TrySetResult(res);
return res;
});
return tcs.Task;
}
Now you can await MyAsyncFunction

C# wait DLL async method to finish

I have a DLL which has public Task<> method which returns return Task.Factory.StartNew(() => ...). I am calling it within a program and I want the program to wait for the execution of the task to finish before it continues doing other things. I've added Thread.Sleep(6000) to the DLL to simulate longer execution.
When I'm calling it like this
var invokedTask = myMethod.Invoke(Activator.CreateInstance(myClass), myParams);
It just continues with execution (as expected). But then I tried this:
var invokedTask = Task.Factory.StartNew(() => myMethod.Invoke(Activator.CreateInstance(myClass), myParams));
invokedTask.Wait();
And it doesn't work. How can I make it wait from outside of DLL?
Just Wait for the task that is being returned - don't spin up another Task just to call the original method:
var invokedTask = (Task)myMethod.Invoke(Activator.CreateInstance(myClass), myParams);
invokedTask.Wait();
I think the calling method must have the async keyword in the definition:
async void (or Task) MyCaller()
{
await Task.Factory.StartNew(() => myMethod.Invoke(Activator.CreateInstance(myClass), myParams));
}
void or Task depends on which context you are in.
When you wait() a Task.Factory.StartNew() the result is a Task
Therefore you have to call wait() two times or you can use await operator.
Therefore you can do the following.
var invokedTask = Task.Factory.StartNew(() => myMethod.Invoke(Activator.CreateInstance(myClass), myParams));
var result=await await invokedTask;
Or you can do the following
var invokedTask = Task.Factory.StartNew(() => myMethod.Invoke(Activator.CreateInstance(myClass), myParams));
invokedTask.Wait();
var resultTask=invokedTask.Result;
resultTask.Wait();
var result=resultTask.Result;
However from the question you have posted, it looks like your myMethod.Invoke() returns Task.Factor.StartNew() therefore I would like you to try
var result =await await myMethod.Invoke(Activator.CreateInstance(myClass), myParams);
However it is a bad practice to use Wait() and then Result() as it block the current thread.
Therefore I would like you to use await.
This example may help:
public class MagicClass
{
private int magicBaseValue;
public MagicClass()
{
magicBaseValue = 9;
}
public Task<int> ItsMagic(int preMagic)
{
return Task.Factory.StartNew(() => preMagic * magicBaseValue);
}
}
public class TestMethodInfo
{
public static void Main()
{
// Get the ItsMagic method and invoke with a parameter value of 100
Type magicType = typeof(MagicClass);
MethodInfo magicMethod = magicType.GetMethod("ItsMagic");
var magicValue = ((Task<int>)(magicMethod.Invoke(Activator.CreateInstance(typeof(MagicClass)), new object[] { 100 }))).Result;
Console.WriteLine("MethodInfo.Invoke() Example\n");
Console.WriteLine("MagicClass.ItsMagic() returned: {0}", magicValue.ToString());
Console.ReadKey();
}
}
You can cast your Invoke as a Task<> and then get the Result. This will wait until the method is done executing.

Await new Task<T>( ... ) : Task does not run?

A continuation of a question asked here :
In the aforementioned question I have the following function which returns an object of type Task (for incremental testing purposes) :
private static Task<object> GetInstance( ) {
return new Task<object>( (Func<Task<object>>)(async ( ) => {
await SimpleMessage.ShowAsync( "TEST" );
return new object( );
} ) );
}
When I call await GetInstance( );, the function is called (and I assume the task is returned since no exception is thrown) but then the task just sits there.
I can only guess I am doing this wrong then.
I do not want this function to return a task that is already running ( that is IMPERATIVE ).
How do I asynchronously run the task returned by this function?
To create a Task already started
Try creating the task like this:
Task.Factory.StartNew<object>((Func<Task<object>>) ...);
To create a Task without starting it
If you don't want the task started, just use new Task<object>(...) as you were using, but then you need to call Start() method on that task before awaiting it!
[Reference]
My recommendation
Just make a method that returns the anonymous function, like this:
private static Func<object> GetFunction( ) {
return (Func<object>)(( ) => {
SimpleMessage.Show( "TEST" );
return new object( );
} );
}
Then get it and run it in a new Task whenever you need it (Also notice that I removed the async/await from the lambda expression, since you are putting it into a Task already):
Task.Factory.StartNew<object>(GetFunction());
One advantage to this is that you can also call it without putting it into a Task:
GetFunction()();
You should never use the Task constructor (or Task.Start).
I do not want this function to return a task that is already running ( that is IMPERATIVE ).
So, you want to return some code that won't execute until you call it? That's a delegate, not a Task.
private static Func<Task<object>> GetInstance()
{
return async () =>
{
await SimpleMessage.ShowAsync("TEST");
return new object();
};
}
When you're ready to execute it, call it just like any other delegate. Note that it returns a Task, so you can await the result:
var func = GetInstance();
// Delegate has not started executing yet
var task = func();
// Delegate has started executing
var result = await task;
// Delegate is done
You are stuck with a bad design there. I'll try to make something work for you under these constraints.
The only way to delay start tasks is to use the Task.Start method. (You also can use RunSynchronously but that doesn't really make use of any of the tasks features. At this point the task becomes an unthreaded lazy object.
So use the Task.Start method.
await does not start tasks. It waits for tasks that already run. Therefore await new Task(() => { }) always freezes forever.
Another problem here:
return new Task<object>( (Func<Task<object>>)(async ( ) => {
await SimpleMessage.ShowAsync( "TEST" );
return new object( );
} ) );
When you start that task it will complete nearly instantly and Task.Result will hold another task - the one returned by the async lambda. I doubt this is what you want. Hard to make this work and I don't know what you need.
This smells like the XY problem. Can you elaborate on what you want to accomplish? It feels like you have given yourself unnecessary constraints.
OK, I think I've figured this out. Please examine this code:
class Program
{
public static void Main(string[] args)
{
// Only RUN the task as needed. FooGet
// still allows you to generalize your task.
Task.Run(() =>
{
dynamic value = FooGet();
value.RunSynchronously();
Console.WriteLine(value.Result.Result.ToString());
});
while (true) Thread.Sleep(100);
}
private static Task<object> FooGet()
{
var task = new Task<object>(() => {
return asyncBar();
});
return task;
}
private async static Task<object> asyncBar()
{
// do work!
return "Hello, world!";
}
}

How can I convert a function with a ref paramter to an async function?

I have the following function which I want to convert to an async / non locking function.
Here is the function in its currenc form:
private static void BlockForResponse(ref bool localFlag)
{
int count = 0;
while (!localFlag)
{
Thread.Sleep(200);
if (count++ > 50) // 200 * 50 = 10 seconds
{
//timeout
throw new TimeOutException();
}
}
}
here is my attempt:
private static async Task BlockForResponse(ref bool localFlag)
{
int count = 0;
while (!localFlag)
{
await Task.Delay(200);
if (count++ > 50) // 200 * 50 = 10 seconds
{
//timeout
throw new TimeOutException();
}
}
}
however I get a compile error saying that async functions cant have ref or out parameters. However this is the core functionality of the function.
Is it possible to convert it to an async function?
Explanation of code:
I must admit this is an odd piece of code, let me try an explain what its trying to do:
so there is a 3rd party dll which I need to use. Which provides me with services, I sadly have no control over this dll.
The way it works,
I call a command in the dll providing it a callback function which it calls once it has finished the task.
I can only move on to what I want to do once I have the result from that call. hence the need fro this function.
I make the call to the dll, providing it with a call back function:
private bool _commandFlag = false;
private bool _commandResponse;
public async Task ExecuteCommand(string userId, string deviceId)
{
var link = await LinkProviderAsync.GetDeviceLinkAsync(deviceId, userId);
try
{
//execute command
if (link.Command(Commands.ConnectToDevice, CallBackFunction))
{
BlockForResponse(ref _commandFlag);
return; //Received a response
}
else
{ //Timeout Error
throw new ConnectionErrorException();
}
}
catch (Exception e)
{
throw e;
}
}
private void CallBackFunction(bool result)
{
_commandResponse = result;
_commandFlag = true;
}
The way it works, I call a command in the dll providing it a callback function which it calls once it has finished the task.
Then what you really want is to use TaskCompletionSource<T> to create a TAP method, something similar to this.
public static Task<bool> CommandAsync(this Link link, Commands command)
{
var tcs = new TaskCompletionSource<bool>();
if (!link.Command(command, result => tcs.TrySetResult(result)))
tcs.TrySetException(new ConnectionErrorException());
return tcs.Task;
}
With this extension method in place, your calling code is much cleaner:
public async Task ExecuteCommand(string userId, string deviceId)
{
var link = await LinkProviderAsync.GetDeviceLinkAsync(deviceId, userId);
var commandResponse = await link.CommandAsync(Commands.ConnectToDevice);
}
The problem with combining async and ref is that code inside an async function can run even after the method returns. So, if you did something like:
async Task BlockForResponseAsync(ref bool localFlag)
{
while (!localFlag)
{
...
}
}
void SomeMethod()
{
bool flag = false;
BlockForResponseAsync(ref flag); // note: no await here
}
Then the local variable flag would stop existing after SomeMethod() returned, but BlockForResponseAsync(), which has a reference to that variable, could still be executing. This is why the above code won't compile.
Basically, what you need is a closure, and in C#, ref doesn't create closures, but lambdas do. This means you can write your method like this:
async Task BlockForResponseAsync(Func<bool> localFlagFunc)
{
while (!localFlagFunc())
{
...
}
}
And use it like this:
bool flag = false;
var task = BlockForResponseAsync(() => flag);
// other code here
flag = true;
await task; // to make sure BlockForResponseAsync() completed successfully
This way also indicates your intention better. ref usually means something like: "give me a variable with some value, and I will change that value", which is not what you want here. On the other hand Func<T> means "give me something that I can use retrieve some value, potentially multiple times".

Categories

Resources