async Indexer in C# - 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).

Related

awaiting inside an awaitable function in .net

I have a function that returns a Task
class Sample
{
TaskCompletionSource<int> _tcs;
..
public Task<int> DoIt(){
StartDoingStuff();
return _tcs.Task;
}
..
private void FinshedStuffCallBack(){
_tsc.SetResult(42);
}
}
Caller goes
var sample = new Sample();
var result = await Sample.DoIt();
works fine
Now I need to do something in addition in DoIt, this is itself awaitable
I naively tried
public async Task<int> DoIt(){
await DoOtherAsyncStuff();
StartDoingStuff();
return _tcs.Task;
}
but this is not allowed
CS4016 Since this is an async method, the return expression must be of
type 'int' rather than 'Task'
OK I get what its trying to say, but thats not my intention, I dont have the return value yet, it comes once StartDoingStuff triggers the callback.
Not sure what to try next.
Most likely you just need (note the await on the last line):
public async Task<int> DoIt()
{
await DoOtherAsyncStuff();
StartDoingStuff();
return await _tcs.Task;
}
await is needed on the last line because an async function returning Task<int> needs to return int, while _tcs.Task is a Task<int>. Using await will wait for the Task's completion and return the int which is what we need.
However, depending on your complete code you may want something else. For example if you're doing more complicated things with TaskCompletionSource you may need to remove async for this definition and do something like
public Task<int> DoIt()
{
return DoOtherAsyncStuff().ContinueWith(_ =>
{
StartDoingStuff();
return _tcs.Task;
}, TaskCompletionOptions.ExecuteSynchronously);
}
In general it's best not to mess with TaskCompletionSource unless you're doing something more advanced, for example providing an async abstraction of something synchronous/callback based. Hence a complete code example may change my answer (for example what's the body of StartDoingStuff + DoOtherAsyncStuff?).

c#: Chain asynchronous methods

I've found a piece of code showing how to chain asynchronous methods. Here is the code:
public static class ExtensionMethod
{
public static async Task<TResult> MapAsync<TSource, TResult>(
this Task<TSource> #this,
Func<TSource, Task<TResult>> fn)
{
return await fn(await #this);
}
}
public partial class Program
{
public async static Task<int> FunctionA
(int a) => await Task.FromResult(a * 1);
public async static Task<int> FunctionB(
int b) => await Task.FromResult(b * 2);
public async static Task<int> FunctionC(
int c) => await Task.FromResult(c * 3);
public async static void AsyncChain()
{
int i = await FunctionC(10)
.MapAsync(FunctionB)
.MapAsync(FunctionA);
Console.WriteLine("The result = {0}", i);
}
}
But I don't understand why inside the extension method MapAsync we have await fn(await #this)?
Can someone explain me this, please?
The reason for this is because in order to get the value of the previous call (in this case the value stored within the Task #this) it must be awaited. Because await is now being used in the method and it must be marked as async, you can now no longer simply return the result from fn because it's a Task. (As I'm sure you are aware, and in very simple terms, marking the method as async means that the method signature sort of ignores the Task and just wants an instance of the generic type as the return or nothing if it's not using the genric version of Task.)
In response to your comment about chaining both sync vs async methods, this approach of using Task would still work for sync methods, you just have to pretend that its async by wrapping the result in a task (which is already marked as completed). Something like this:
public async static Task<int> AsyncFunction(int x)
=> await SomeAsyncMethodThatReturnsTaskOfInt();
public static Task<int> SyncFunction(int x)
=> Task.FromResult(SomeSyncMethodThatReturnsInt());
public async static void AsyncChain()
{
int i = await AsyncFunction(10)
.MapAsync(SyncFunction);
Console.WriteLine("The result = {0}", i);
}
You can remove all the async/awaits from the FunctionA, FunctionB and FunctionC definitions as they can just return the task.
There is a nice article on Eliding await by Stephen Cleary for a better explanation of when you should and shouldn't use await when the only thing the method is doing is returning Task.
Having said all that, Gusman's comment is completely correct that this is total overkill for a fairly simple ContinueWith

Task return type with and without Async [duplicate]

This question already has answers here:
Why use async and return await, when you can return Task<T> directly?
(9 answers)
Closed 5 years ago.
I little bit confused on the behavior of the async keyword.
Lets say I have 2 methods,
public async Task DoSomething1()
{
await Task.Run(() =>
{
for(int i = 0; i<3; i++)
{
Console.WriteLine("I m doing something:" + i);
}
});
}
And
public Task DoSomething2()
{
return Task.Run(() =>
{
for(int i = 0; i<3; i++)
{
Console.WriteLine("I m doing something:" + i);
}
});
}
From my understanding both methods are awaitable. But when I write a method that has a Task return type without the async keyword I need to return a Task otherwise the compiler generates an error. Its a common thing that a method should return its type. But when I use it with the async keyword the compiler generates another error that you can't return a Task. So what does it mean? I am totally confused here.
General Async Info
If you use await in your code, you are required to use the async keyword on the method.
If you use async and want to return an actual type, you can declare that your method returns the type as a generic Task like this Task<int>.
Here are the valid return types for an async method:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/async-return-types
Task<TResult>, for an async method that returns a value.
Task, for an async method that performs an operation but returns no value.
void, for an event handler.
A new answer August 2022
TL;DR - The return type is automatically wrapped in a Task.
I was receiving downvotes on this so I re-read the question in more detail and got to the root of it. It's not about the return type in the signature of the method. Its about the return value. Also it is not a duplicate question!
Anyway, let's look at this method:
public Task TaskMethod()
{
return Task.CompletedTask;
}
This seems pretty normal and what we are used to in C#. You declare the return type and return an object of that type. Easy. (In fact the "lowered" code is the exact same.)
Now for the async case.
public async Task MethodAsync()
{
return Task.CompletedTask;
}
This generates a compile error: error CS1997: Since 'C.MethodAsync()' is an async method that returns 'Task', a return keyword must not be followed by an object expression. Did you intend to return 'Task<T>'?
OK, then we can't return a task directly, let's do the right thing. It is easier to see this example if we return something so, let's return int.
public async Task<int> MethodAsync()
{
return 1;
}
(This method gives a warning that we are using async without await, but ignore this for now.)
The lowered code is complicated, but you can see that a state machine will be generated. The MethodAsync looks like this:
[CompilerGenerated]
private sealed class <MethodAsync>d__0 : IAsyncStateMachine
{
public int <>1__state;
public AsyncTaskMethodBuilder<int> <>t__builder;
public C <>4__this;
private void MoveNext()
{
int num = <>1__state;
int result;
try
{
result = 1;
}
catch (Exception exception)
{
<>1__state = -2;
<>t__builder.SetException(exception);
return;
}
<>1__state = -2;
<>t__builder.SetResult(result);
}
void IAsyncStateMachine.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
this.MoveNext();
}
[DebuggerHidden]
private void SetStateMachine(IAsyncStateMachine stateMachine)
{
}
void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
{
//ILSpy generated this explicit interface implementation from .override directive in SetStateMachine
this.SetStateMachine(stateMachine);
}
}
[AsyncStateMachine(typeof(<MethodAsync>d__0))]
[DebuggerStepThrough]
public Task<int> MethodAsync()
{
<MethodAsync>d__0 stateMachine = new <MethodAsync>d__0();
stateMachine.<>t__builder = AsyncTaskMethodBuilder<int>.Create();
stateMachine.<>4__this = this;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
And you can see the Task here is automatically returned in the public method. The state machine implements the method body.
You can see that the actual value returned is the int from <>t__builder wrapped in a Task.
To see the lowered code yourself, you can try it in https://sharplab.io.
Also after writing all this I found another answer that explains it in a different way. Guess who wrote that answer?
https://stackoverflow.com/a/37647093/1804678
(...) “async”. This keyword
allows that inside the method the word “await” can be used, and
modifies how its result is handled by the method. That’s it.
The method runs synchronously until it finds the word “await” and that
word is the one that takes care of asynchrony. “Await” is an operator
that receives a parameter: an awaitable (an asynchronous operation)
behaves in this way:
From here

Await an async function from setter property

I need to await to an async function from a property setter method.
public String testFunc()
{
get
{
}
set
{
//Await Call to the async func <asyncFunc()>
}
}
I understand we should not make async properties, so what is the optimal way to do this.
You can't make async properties and you shouldn't want to - properties imply fast, non blocking operations. If you need to perform a long running activity, as implied by you're wanting to kick of an async operation and wait for it, don't make it a property at all.
Remove the setter and make a method instead.
Use
public bool SomeMethod
{
get { /* some code */ }
set
{
AsyncMethod().Wait();
}
}
public async Task AsyncMethod() {}
[EDIT]
You can't use async function with property
Alternative Can use Result Property
public string UserInfo
{
get => GetItemAsync().Result;
}

What's the best way to wrap a Task as a Task<TResult>

I am writing some async helper methods and I have APIs to support both Task and Task<T>. To re-use code, I'd like the Task-based API to wrap the given task as a Task<T> and just call through to the Task<T> API.
One way I can do this is:
private static async Task<bool> Convert(this Task #this)
{
await #this.ConfigureAwait(false);
return false;
}
However, I'm wondering: is there there is a better/builtin way to do this?
There is no existing Task method that does exactly this, no. Your method is fine, and is likely about as simple as you'll be able to get.
Implementing the proper error propagating/cancellation semantics using any other method is deceptively hard.
Updated, the following propagates exceptions and cancellation:
public static class TaskExt
{
public static Task<Empty> AsGeneric(this Task #this)
{
return #this.IsCompleted ?
CompletedAsGeneric(#this) :
#this.ContinueWith<Task<Empty>>(CompletedAsGeneric,
TaskContinuationOptions.ExecuteSynchronously).Unwrap();
}
static Task<Empty> CompletedAsGeneric(Task completedTask)
{
try
{
if (completedTask.Status != TaskStatus.RanToCompletion)
// propagate exceptions
completedTask.GetAwaiter().GetResult();
// return completed task
return Task.FromResult(Empty.Value);
}
catch (OperationCanceledException ex)
{
// propagate cancellation
if (completedTask.IsCanceled)
// return cancelled task
return new Task<Empty>(() => Empty.Value, ex.CancellationToken);
throw;
}
}
}
public struct Empty
{
public static readonly Empty Value = default(Empty);
}
I've had the same requirement recently and I solved it with my own helper extension method, which allows the user to effectively wrap a Task with a Task<T>:
public static async Task<TResult> WithCompletionResult<TResult>(
this Task sourceTask,
TResult result
)
{
await sourceTask;
return result;
}
In your example call with:
Task<bool> task = myTask.WithCompletionResult<bool>(false);
If the result of Task<T> does not matter, I will use:
Task<object> task = myTask.WithCompletionResult<object>(null);
I hope this helps. If anyone knows of a pitfall with this approach let me know!
Using await seems a bit overkill here. No need for the state machine here, just use a ContinueWith
private static Task<bool> Convert(this Task #this)
{
return #this.ContinueWith(p => { p.Wait(); return false;});
}
Note: This will result in an AggregateException being wrapped unfortunately

Categories

Resources