[英]Best way to write an async method in C#
我有一個服務 object,它只是對 Microsoft SQL 數據庫之上的 EF Core 存儲庫執行查詢。 我正在嘗試將這些同步方法轉換為異步版本。 這是一種簡化方法的示例...
同步版本
public List<Contact> GetContacts()
{
var ret = this.dbContext.Contacts.ToList();
return ret;
}
我已經看到了幾種不創建 ASYNC 方法的方法......然后又......我看到了幾種不同的方法來說明你應該如何創建異步方法。 我陷入了以下兩種方法中的哪一種被認為是創建異步方法的“正確”或“最佳”方法之間。
異步版本 1
public Task<List<Contact>> GetContactsAsync()
{
return Task.FromResult(this.dbContext.Contacts.ToList());
}
或者
異步版本 2
public async Task<List<Contact>> GetContactsAsync()
{
List<Contact> ret = null;
await Task.Run(()=>{
ret = this.dbContext.Contacts.ToList();
});
return ret;
}
如果查詢包含多行邏輯,則可能使這進一步復雜化。
這是包含更多細節的相同方法。 如果您看到除了異步主題之外的問題,那么我很樂意在 PM 或其他內容中聽到它們,但是對於這個線程,我想專注於等待/異步的東西。
完整的同步代碼
public PaginationResult<Contact> GetContacts(PaginationSpec pagingSpec, List<Expression<Func<Models.Contact, bool>>> filter = null)
{
IQueryable<Contact> query = ContactService.GetContactQuery(this.ctx);
if (filter != null && filter.Count > 0)
{
foreach (var item in filter)
{
query = query.Where(item);
}
}
// get the record count
//
var recordcount = query.Count();
// get the pagination
//
var stage = pagingSpec.ApplyPagination<Models.Contact>(query);
// Construct the paged result.
//
var ret = new PaginationResult<Models.Contact>(recordcount, pagingSpec.CurrentPage, pagingSpec.PageSize, stage.ToList());
return ret;
}
我將如何將其包裝在適當的語法中以使此方法異步? 我可以想到幾個方法...
異步版本 1
public Task<PaginationResult<Contact>> GetContactsAsync(PaginationSpec pagingSpec, List<Expression<Func<Models.Contact, bool>>> filter = null)
{
return Task.FromResult(GetContacts(pagingSpec, filter)) // simply call the synchronous method ??;
}
或者
異步版本 2
public async Task<PaginationResult<Contact>> GetContactsAsync()
{
PaginationResult<Contact> ret = null;
await Task.Run(()=>{
// Encapsulate the execution code within the RUN method ??
//
IQueryable<Contact> query = ContactService.GetContactQuery(this.ctx);
if (filter != null && filter.Count > 0)
{
foreach (var item in filter)
{
query = query.Where(item);
}
}
// get the record count
//
var recordcount = query.Count();
// Apply the pagination spec to the query
//
var stage = pagingSpec.ApplyPagination<Models.Contact>(query);
// Construct the esult.
//
ret = new PaginationResult<Models.Contact>(recordcount, pagingSpec.CurrentPage, pagingSpec.PageSize, stage.ToList());
});
return ret;
}
這些中的任何一個都不合適,比一個或另一個更好,還是我錯過了第三個選項?
嘗試學習這個等待/異步的東西,任何幫助表示贊賞! 謝謝!
這兩者通常被認為是不正確的。
異步版本 1
這個問題是它實際上不是異步的。 它只是做相同的同步工作並將其包裝在Task<T>
中。
異步版本 2
這個問題是從調用者的角度來看它是異步的,但在其實現中是同步的。 它只是使用Task.Run
在線程池線程上運行同步代碼,因此它看起來是異步的。 這就是我所說的“假異步”,這對於桌面應用程序來說是可以的(不理想),當然不推薦用於 ASP.NET 應用程序。
更合適的解決方案如下所示:
public async Task<List<Contact>> GetContactsAsync()
{
return await this.dbContext.Contacts.ToListAsync();
}
這是假設您有可用的ToListAsync
方法。 注意與同步版本的相似之處:
public List<Contact> GetContacts()
{
return this.dbContext.Contacts.ToList();
}
一般來說,您希望從最低級別開始,即實際執行IQueryable
的代碼。 在這種情況下,我假設那是ToList
,但如果ToList
是您自己的方法,那么它可能是該方法調用的任何方法。 一旦找到最低級別的代碼,然后將其更改為使用await
,並讓 async 從那里增長。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.