Async Lambda Func<string> - c#

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

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.

Cannot implicitly convert type 'void' to 'object' on GetAwaiter().GetResult()

We have used the following code to await method execution since we have sync methods that must consume async methods and this is a wrapper we have used in our project
public dynamic RunTask(dynamic method) {
var result = Task.Run(async () => await method).ConfigureAwait(false);
return result.GetAwaiter().GetResult();
}
Seems like this line of code works fine when the method have return types ex: Task< int > but today when I have written non-return method it throws an exception when there is no return value from Task
// throws exception in this case 'Cannot implicitly convert type 'void' to 'object'
public async Task Run(){
await //;
}
// Works
public async Task<int> Fun(){
return await //;
}
From the message, it is clearly unable to assign void to object but is there something I am missing how do I make it work void tasks. We are using .net core 3.1. Any help is greatly appreciated.
Are you calling RunTask(); with the method not returning anything? :)
You can try this code for your purpose, however as Marc suggested, this is not recommended practice:
public dynamic RunTask(dynamic method)
{
if (method is Task)
{
method.ConfigureAwait(false).GetAwaiter().GetResult();
return 0;
}
else
{
var result = Task.Run(async () => await method).ConfigureAwait(false);
return result.GetAwaiter().GetResult();
}
}
First of this a bad practice. The best way to async call is following await pattern. This goes something like this
private Task MyMethodAsync(){
}
public async void Main(){
await MyMethodAsync();
}
Now it can be a bit difficult to implement await pattern if it's not already in place (as it may require await-ing all the calls in chain). What you can you do is the following:
MyMethodAsync().Wait()
This will block the calling thread and wait till the task is done. Since it's void you won't get any result and that's the main reason you are getting this exception in the first place.

How can I call an async method inside an anonymous delegate?

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

async Indexer in C#

Recently, we have movied to EF 6 and we have begun to use EF async commands.
For example in my repository I have the following method:
// Gets entities asynchron in a range starting from skip.
// Take defines the maximum number of entities to be returned.
public async Task<IEnumerable<TEntity>> GetRangeAsync(int skip, int take)
{
var entities = this.AddIncludes(this.DbContext.Set<TEntity>())
.OrderBy(this.SortSpec.PropertyName)
.Skip(skip)
.Take(take)
.ToListAsync();
return await entities;
}
Now I have to modfiy the UI for the async data retrieving.
Below is my UI class; This class is bound to WPF.
public sealed class RepositoryCollectionView<TEntity, TEntityViewModel> : IList<TEntityViewModel>,
ICollectionView,
IEditableCollectionView,
IComparer
...
public TEntityViewModel this[int index]
{
get
{
return await this.GetItem(index).Result;
}
set
{
throw new NotSupportedException();
}
}
...
...
...
The problem: In the UI I have create a new method which called GetItemAsync(index) and I need to call this method from the Indexer;
When I write the keyword async to the indexer like that:
public async TEntityViewModel this[int index] I get the following error "The modfier 'async' is not valid for this item"
Any idea? any help would be greatly appreciated!
You simply can't make indexers async. From section 10.15 of the C# 5 specification:
A method or anonymous function with the async modifier is called an async function.
async is listed as one of the valid modifiers for methods (section 10.6), but not for indexers (10.9).
Bear in mind that an async method can only return void, Task and Task<T> - but you wouldn't want a setter to accept a Task<T> or Task, so what would the property type usefully be? (And why even have a setter if you're not supporting it?)
Given that it sound like a caller can already use GetItem - which should be GetItemAsync if it's returning a Task<TEntityViewModel> - I don't see that an indexer is going to help you.
You technically can't make indexers async. You can however have a get indexer return a Task or return the Task from an async method. Which accomplishes the same.
public class AsyncIndexer
{
public Task<int> this[int i] => GetValue(i);
public Task<string> this[string s] => Task.Run(async () =>
{
await Task.Delay(3000);
return s;
});
private async Task<int> GetValue(int i)
{
await Task.Delay(3000);
return i;
}
}
class Program
{
static void Main(string[] args)
{
Task.Run(async () =>
{
var asyncIndexer = new AsyncIndexer();
Console.WriteLine(await asyncIndexer[2]);
}).Wait();
}
}
Unfortunately setters can't return anything, so async setters are in no way possible because the await statement needs a task to be returned.
Could you imagine the syntax?
await (asyncIndexer[2] = 2)
I'd love that :p
This isn't possible properties cannot be async. Source
What you can do is call an asyncrounous method and wait for it to complete, but it will block (no async means no await).

Categories

Resources