这是重新配置构造函数以使用异步和等待的正确方法吗?

XJo*_*neX 0 c# asynchronous async-await

我读过几篇文章,但我很难理解这一点。我试图在加载一些数据时保持 MAUI 应用程序的 UI 更新。

我想完成这个:

async public DataService()
{
    //initialize stuff here
    await this.GetPayees();
    await this.GetCategories();
    return;
}
Run Code Online (Sandbox Code Playgroud)

我读到你不能有异步构造函数,所以我不得不重做如何初始化我的类。

public DataService()
{
    //Take this out here
    //this.GetPayees();
    //this.GetCategories();
    return;
}

async public static Task<DataService> BuildDataServiceAsync()
{
    //await them here
    var dataService = new DataService();
    await dataService.GetPayees();
    await dataService.GetCategories();
    return dataService;
}
Run Code Online (Sandbox Code Playgroud)

这对我的代码产生了连锁效应。我必须将返回类型更改为任务,并使其他方法异步

async public Task<List<Payee>> GetPayees()
{
    //Load arbitrary data, 
    if(Payees.Count != 0) return Payees;
    Payees.Add(new Payee { Id = 0, Name = "Food Lion", DefaultCategoryId = 0, DefaultIsCredit = false });
    Payees.Add(new Payee { Id = 1, Name = "Work Incorporated", DefaultCategoryId = 1, DefaultIsCredit = true });
    Payees.Add(new Payee { Id = 2, Name = "Hardees", DefaultCategoryId = 3, DefaultIsCredit = false });
    Payees.Add(new Payee { Id = 3, Name = "Wal-Mart", DefaultCategoryId = 5, DefaultIsCredit = false });
    Payees.Add(new Payee { Id = 4, Name = "Aldis", DefaultCategoryId = 0, DefaultIsCredit = false });
    Payees.Add(new Payee { Id = 5, Name = "McDonalds", DefaultCategoryId = 3, DefaultIsCredit = false });
    Payees.Add(new Payee { Id = 6, Name = "Harris Teeter", DefaultCategoryId = 0, DefaultIsCredit = false });
    Payees.Add(new Payee { Id = 7, Name = "Shoe Show", DefaultCategoryId = 2, DefaultIsCredit = false });
    Payees.Add(new Payee { Id = 8, Name = "Capital One", DefaultCategoryId = 4, DefaultIsCredit = false });
    Payees.Add(new Payee { Id = 9, Name = "Dicks Sporting Goods", DefaultCategoryId = 6, DefaultIsCredit = false });
    Payees.Add(new Payee { Id = 10, Name = "Amazon", DefaultCategoryId = 7, DefaultIsCredit = false });
    return Payees;
}

async public Task<List<Category>> GetCategories()
{
    if(Categories.Count != 0) return Categories;
    Categories.Add(new Category { Id = 0, Name = "Groceries" });
    Categories.Add(new Category { Id = 1, Name = "Paycheck" });
    Categories.Add(new Category { Id = 2, Name = "Shoes" });
    Categories.Add(new Category { Id = 3, Name = "Fast Food" });
    Categories.Add(new Category { Id = 4, Name = "Credit Card" });
    Categories.Add(new Category { Id = 5, Name = "Supplies" });
    Categories.Add(new Category { Id = 6, Name = "Recreation" });
    Categories.Add(new Category { Id = 7, Name = "Grocery" });
    Categories.Add(new Category { Id = 8, Name = "Gross" });
    Categories.Add(new Category { Id = 9, Name = "Grass" });
    return Categories;
}
Run Code Online (Sandbox Code Playgroud)

我收到编译器关于在最后两种方法中没有等待的警告。我真的会等待所有的 Add() 吗?

我刚刚让依赖注入按照我想要的方式工作,但这一切都级联回我的视图模型,其中注入了我的依赖项:

public PayeesViewModel(DataService dataService, NavigationService navigationService, ValidationService validationService)
{
    this.dataService = dataService;
    this.navigationService = navigationService;
    this.validationService = validationService;
    Payees = await dataService.GetPayees();
    Categories = await dataService.GetCategories();

    for(int x = 0; x < Payees.Count; x++)
    {
        PayeeDisplay.Add(new PayeeDisplay
        {
            Id = Payees[x].Id,
            Name = Payees[x].Name,
            DefaultCategory = Categories.Find(c => c.Id.Equals(Payees[x].DefaultCategoryId)).Name,
            DefaultCategoryId = Payees[x].DefaultCategoryId,
            DefaultIsCredit = Payees[x].DefaultIsCredit
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

我是否以错误的方式处理这个问题?尝试采用 async/await 实际上会毁掉我的项目。

Gab*_*uci 5

async关键字仅允许使用await. 如果你不需要使用await,那么你就不需要async

List.Add()不是异步方法,因此您不会使用await. 所以只需删除async关键字即可;你不需要它。

当 CPU 必须等待外部资源时,异步编程很有用,例如:网络请求、文件存储请求等 - 任何不在 CPU 或 RAM 内部的资源。将对象添加到集合纯粹是内存中操作,因此不太适合异步编程。

我认为阅读 Microsoft 关于使用 async 和 wait 进行异步编程的文档会让您受益匪浅。写得相当好。


更新:

既然您说对的调用Add()只是 SQL 访问的占位符,那么是的,您希望用于asyncSQL 调用,并且您的做法是正确的:创建一个public static async方法来为您创建该类的实例。这称为“工厂方法”。您甚至可以更进一步,将构造函数设为私有,这样您就可以强制使用工厂方法:

private DataService() {}

public static async Task<DataService> BuildDataServiceAsync()
{
    var dataService = new DataService();
    await dataService.GetPayees();
    await dataService.GetCategories();
    return dataService;
}
Run Code Online (Sandbox Code Playgroud)

GetPayees()如果GetCategories()必须调用私有构造函数才能使对象处于可用状态,则拥有私有构造函数非常重要。