How can I call an async method inside an anonymous delegate? - c#

I have a function takes a delegate as input parameter.
public delegate bool Callback();
public static class MyAPI
{
public static handle(Callback callback) {
...
}
}
So I call the api with an anonymous delegate like this
MyAPI.handle(delegate
{
// my implementation
});
My question is how can i call an async method in my anonymous delegate?
MyAPI.handle(delegate
{
// my implementation
await MyMethodAsync(...);
});
I get an error saying the 'await' operator can only be used within async anonymous method'?
The function MyAPI.handle() only expect a non async delegate. I can't change that method. How can I fix my problem?
Thank you.

You could call an asynchronous method by passing an async lambda expression:
MyAPI.handle(async () =>
{
// my implementation
await MyMethodAsync(...);
});

MyAPI.handle(async () =>
{
// my implementation
await MyMethodAsync(...);
});

Another solution for people like me that don't really like how lambdas look.
MyAPI.handle(
async delegate() {
// my implementation
await MyMethodAsync(...);
}
);

Related

MethodInfo.CreateDelegate with async Task return type

I have this method,
public void SomeMethod() { ... }
And I can create delegate using reflection without issue,
var action = (Action)method.CreateDelegate(typeof(Action), this);
...
action.Invoke();
However, if I replace the void to async Task return type, I get this error,
Cannot bind to the target method because its signature is not compatible with that of the delegate type.
I cannot find the way how to create the delegate and invoke it if the method is like this,
public async Task SomeMethod() { ... }
or like this,
public async Task<SomeObject> SomeMethod() { ... }
Thanks for the help.
If I understand your question correctly
Given
public async Task SomeBob() { ... }
I guess you are looking for
MethodInfo method = //<Some wonderful reflection here>
var bob = (Func<Task>)method.CreateDelegate(typeof(Func<Task>), this);
await bob();
or
(Func<Task<SomeType>>)method.CreateDelegate(typeof(Func<Task<SomeType>>), this);
Though as to way you are doing this or need to do this, I am not sure

Async void lambda expressions

A quick google search will tell you to avoid using async void myMethod() methods when possible. And in many cases there are ways to make it possible. My question is basically an offshoot of this best practice:
What does the lambda expression below evaluate to?
Task.Run( async ()=> await Task.Delay(1000));
If it becomes an async Task then we are following best practice.
But what if it evaluates to async void?
The documentation for expression lambdas says,
An expression lambda returns the result of the expression
So, for example, () => "hi" returns a string, even though there is no return statement. But if the expression doesn't return anything, like in () => Console.WriteLine("hi"), then it's considered void.
However there is a bit of trickery with async lambdas. The expression await Task.Delay(1000) doesn't really return anything in itself. However, the language can figure out that if you have an async lambda, you likely want it to return a Task. So it will prefer that.
So this:
Task.Run(async () => await Task.Delay(1000));
Is equivalent to this, if you were to express it with a named method:
private async Task Wait1000() {
await Task.Delay(1000);
}
Task.Run(Wait1000);
But it is important to note that async lambdas can be inferred to be async void. The only reason it is considered async Task here is because Task.Run has an overload for Func<Task>. If the only available overload took an Action parameter, then it would be inferred to be async void, without any warning to you.
For example, this produces no error and the lambda is treated as async void:
private void RunThisAction(Action action) {
action();
}
RunThisAction(async () => await Task.Delay(1000));
That is different than if you passed it a named async Task method, which would cause a compiler error:
private void RunThisAction(Action action) {
action();
}
private async Task Wait1000() {
await Task.Delay(1000);
}
RunThisAction(Wait1000); // 'Task Wait1000()' has the wrong return type
So be careful where you use it. You can always hover over the method name (like the Run in Task.Run) and Visual Studio will tell you which overload it has inferred:
Yeah, it is evaluated to async Task because Task.Delay(n) has return type of Task. So it is good practice.
In addition, there is msdn example, but it is a little bit more verbose:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
button1.Click += async (sender, e) =>
{
await ExampleMethodAsync();
textBox1.Text += "\r\nControl returned to Click event handler.\n";
};
}
private async Task ExampleMethodAsync()
{
// The following line simulates a task-returning asynchronous process.
await Task.Delay(1000);
}
}
So the above code could be shortened to:
public Form1()
{
InitializeComponent();
button1.Click += async (sender, e) =>
{
await Task.Delay(1000);
textBox1.Text += "\r\nControl returned to Click event handler.\n";
};
}
}
And now shortened code looks like your code.

Async Lambda Func<string>

I'm a beginner with the async/await and I'm getting an error on my code that I'm not able to figure out how to fix it:
public static Func<string> GetTheID;
void Main()
{
GetTheID = async () => await GetMyId(); //Error here!
Console.WriteLine(GetTheID);
}
public async Task<string> GetMyId()
{
return await Task.Run(() =>
{
return "AAABBBB";
});
}
I'm getting this error:
Cannot convert async lambda expression to delegate type
'Func<string>'. An async lambda expression may return void, Task or
Task<T>, none of which are convertible to 'Func<string>'
Could you please help me how to fix this error without changing the signature of the GetTheID delegate (I means without changing its signature to Func<Task<string>>)?
You have to change the signature of the GetTheID, and there isn't any other way. So as the error suggest, you need to change the type of GetTheID to Func<Task<string>>, it has to return a Task or Task<T> in order to be able to await it:
public static Func<Task<string>> GetTheID;
Starting with C# 7.1, you can actually have an async Main() function, which enables you to use await in the described situation:
static async Task<int> Main(string[] args)
{
return await AsyncConsoleWork();
}
It seems that you are trying to adapt an asynchronous method to work in a synchronous way.
If this is the correct context your approach could be
void Main()
{
GetTheID = () => GetMyId().Result;
Console.WriteLine(GetTheID.Invoke());
}
use this:
void Main()
{
GetTheID = () => GetMyId().GetAwaiter().GetResult();
Console.WriteLine(GetTheID);
}

Check if Action is async lambda

Since I can define an Action as
Action a = async () => { };
Can I somehow determine (at run time) whether the action a is async or not?
No - at least not sensibly. async is just a source code annotation to tell the C# compiler that you really want an asynchronous function/anonymous function.
You could fetch the MethodInfo for the delegate and check whether it has an appropriate attribute applied to it. I personally wouldn't though - the need to know is a design smell. In particular, consider what would happen if you refactored most of the code out of the lambda expression into another method, then used:
Action a = () => CallMethodAsync();
At that point you don't have an async lambda, but the semantics would be the same. Why would you want any code using the delegate to behave differently?
EDIT: This code appears to work, but I would strongly recommend against it:
using System;
using System.Runtime.CompilerServices;
class Test
{
static void Main()
{
Console.WriteLine(IsThisAsync(() => {})); // False
Console.WriteLine(IsThisAsync(async () => {})); // True
}
static bool IsThisAsync(Action action)
{
return action.Method.IsDefined(typeof(AsyncStateMachineAttribute),
false);
}
}
Of course, You can do that.
private static bool IsAsyncAppliedToDelegate(Delegate d)
{
return d.Method.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null;
}
If you're looking to build some logic, based on whether a sync or async lanbda has been passed to your method - just introduce overloads.
public void MyMethod(Action action)
{
DoStuff();
}
public void MyMethod(Func<Task> asyncAction)
{
DoOtherStuff();
}

What's the method signature for passing an async delegate?

I've recently moved back to C# from being in Objective-C land, and the async/await keywords in C# 5 look cool. But I'm still trying to get a handle on the proper syntax.
I want to declare a method that takes an asynchronous delegate as a parameter, but I am having trouble getting both the caller and the callee syntax correct. Can someone provide a code sample showing the method declaration, the call, and a call to the delegate?
I'm thinking the declaration would be something like the following. Note that this function isn't asynchronous; i.e. its asynchronicity is independent of the delegate.
void DoSomethingWithCallback(async delegate foo(int))
{
...
foo(42);
...
}
The call would be something like:
DoSomethingWithCallback(async (int x) => { this.SomeProperty = await SomeAsync(x); });
Of course none of this compiles and most of the samples I've seen assume that one has a field or property that's the delegate, rather than the anonymous delegate I'd like to use.
A function that takes a delegate as a parameter must use a named delegate type; unlike in Objective-C you can't declare an anonymous delegate type inline in the function definition. However, the generics Action<> and Func<> are provided so that you don't have to declare a new type yourself. In the code below I'm assuming the delegate takes a single int as a parameter.
void DoSomethingWithCallback(Func<int,Task> callbackDelegate)
{
Task t = callbackDelegate(42);
}
If this function doesn't actually do anything with the Task object returned (as with the code shown above), you can instead use Action<int> as the delegate type. If you use Action, you can still declare the delegate async (below) but the implicit Task object returned is ignored.
The lambda syntax for calling the above function is straightforward and the syntax you used in the question is correct. Note that the parameter type doesn't need to be specified here since it can be inferred:
DoSomethingWithCallback(async (intParam) => { this.myint = await Int2IntAsync(intParam); });
You can also pass a method or delegate variable, if you wish, instead of using the lambda syntax:
async Task MyInt2Int(int p) { ... }
Func<int,Task> myDelegate;
void OtherMethod()
{
myDelegate = MyInt2Int;
DoSomethingWithCallback(myDelegate); // this ...
DoSomethingWithCallback(MyInt2Int); // ... or this.
}
If I have a task that I want to be passed but not executed, I can wrap the Task in a Func<>, then call that Func<> to create that task. The await can be used in the normal way.
public class Example {
public Example(Func<Task> toBeExecutedInTheFuture)
{
FutureTask = toBeExecutedInTheFuture;
}
public async void ExecuteTaskExample()
{
await FutureTask();
// or alternatively
var myTask = FutureTask();
// do work
await myTask;
}
}
The return type of the method signatue is Task if there is no return type, or Task<T> if there is a return type.
Tho, I'm not 100% certain if you can have async lambdas like that.
In the method that is consuming the task, you would either 'await' the task or use the properties and methods on Task to get the result.
Please take a look to this example, with Task and an additional parameter.
I hope this can help people understanding how to implement it...
// ... more code ...
// Let's call a function with a Task<T> parameter (LocalFunc)
await CustomFunctionAsync(
param1,
LocalFunc
);
// ... more code ...
Declared functions:
public static async Task CustomFunctionAsync(int param1, Func<string, Task<string>> processingFunc = null)
{
string result = null;
if (processingFunc != null)
result = await processingFunc("https://www.google.com/");
}
public async Task<string> LocalFunc(string url)
{
// processing...
}

Categories

Resources