async Indexer in C#

淺唱寂寞╮ 提交于 2021-02-20 07:01:56

问题


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!


回答1:


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.




回答2:


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




回答3:


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



来源:https://stackoverflow.com/questions/22174453/async-indexer-in-c-sharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!