简体   繁体   English

如何在对异步方法的调用上追加对扩展方法的调用

[英]How can I append a call to an extension method on a call to an async method

I have a custom extension method "ToSelectList" and I am currently using it like so: 我有一个自定义扩展方法“ ToSelectList”,目前正在使用它,如下所示:

        var myList = await _myService.GetItems();
        var mySelectList = myList.ToSelectList(nameof(MyEntity.Id));

That's fine and works great, however, I tried to do this as one line: 很好,效果很好,但是我尝试将其作为一行:

        var myList = await _myService.GetItems().ToSelectList(nameof(MyEntity.Id));

But I get: 但是我得到:

'Task<List<MyEntity>>' does not contain a definition for 'ToSelectList'
and no extension method 'ToSelectList' accepting a first argument of type
'Task<List<MyEntity>>' could be found (are you missing a using directive 
or an assembly reference?)

My ToSelectList method is as follows: 我的ToSelectList方法如下:

using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace MyProject.Extensions
{
    public static class ListExtensions
    {
        public static List<SelectListItem> ToSelectList<T>(this List<T> list, string id, string text = "Name")
        {
            var selectListItems = new List<SelectListItem>();

            list.ForEach(item =>
            {
                selectListItems.Add(new SelectListItem
                {
                    Text = item.GetType().GetProperty(text).GetValue(item).ToString(),
                    Value = item.GetType().GetProperty(id).GetValue(item).ToString()
                });
            });

            return selectListItems;
        }
    }

I tried changing method signature to public async static Task<List<SelectListItem>> but no joy. 我尝试将方法签名更改为public async static Task<List<SelectListItem>>但没有任何乐趣。

The problem is that await applies to the entire line so you either need to wrap it in parentheses: 问题是, await应用于整行,因此您需要将其包装在括号中:

var myList = (await _myService.GetItems())
    .ToSelectList(nameof(MyEntity.Id));

Or split it onto 2 lines: 或将其分为两行:

var items = await _myService.GetItems();
var myList = items.ToSelectList(nameof(MyEntity.Id));

While @DavidG 's answer is correct, I would suggest you to simplify your logic. 虽然@DavidG答案是正确的,但我建议您简化逻辑。 You don't need any of that reflection code if you use the built-in Tuple<T1, T2> : 如果使用内置的Tuple<T1, T2>则不需要任何反射代码:

// let's assume this is in your service class
// you most likely want a better name
public Task<List<Tuple<int, string>>> GetItemsAsEnumAsync()
{
    return _context.SomeTable
        .Select(x => Tuple.Create(x.Id, x.Name))
        .ToListAsync();
}

Your ToSelectList would then just be: 您的ToSelectList将会是:

public static List<SelectListItem> ToSelectList(this List<Tuple<int, string>> list)
{
    return list
        .Select(x => new SelectListItem
        {
            Value = x.Item1.ToString(),
            Text = x.Item2
        })
        .ToList();
}

This assumes that your service is not in the same project as the ASP.NET Core application and hence cannot return the List<SelectListItem> itself. 这假定您的服务与ASP.NET Core应用程序不在同一个项目中,因此无法返回List<SelectListItem>本身。 You could make ToSelectList more generic by using ToSelectList<T1, T2>(this List<KeyValuePair<T1, T2>> list) if you find it useful. 如果发现有用,可以使用ToSelectList<T1, T2>(this List<KeyValuePair<T1, T2>> list)使ToSelectList更通用。

You can either go for: 您可以选择:

var myList = _myService.GetItems().Result.ToSelectList(nameof(MyEntity.Id));

but this will just block the thread and you will execute code non async 但这只会阻塞线程,您将执行非异步代码

or change result of _myService.GetItems() to List<SelectListItem> . 或将_myService.GetItems()结果更改为List<SelectListItem>

Anyway what is the point of this async if you immediately need the result? 无论如何,如果您立即需要结果,那么异步的意义是什么?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM