1 回答

TA貢獻1856條經驗 獲得超5個贊
這是您修改為 C# 慣用的代碼async
:
請注意以下事項:
異步代碼通常是指涉及異步 IO 的操作,其中完成信號(和后續完成回調)基本上由硬件中斷和操作系統產生 - 它不應與并發(即多線程)混淆,即使在另一個線程上運行的代碼也可以在概念上被建模為 a
Task
too(實際上,Task
用于多線程 (Task.Run
) 和 async-IO)。無論如何,重點是:如果您使用的是
async
-IO API(例如SqlDataReader
、FileStream
、NetworkStream
等),那么您可能不想使用Task.Run
.除了必須在 UI 線程中運行的代碼(即 WinForms 和 WPF UI 代碼)之外,您應該始終使用它
.ConfigureAwait(false)
來允許在可用的后臺線程中調用完成回調,這意味著 UI 線程不會被迫運行后臺代碼.C# 語言設計人員意識到必須發送垃圾郵件的可怕人體工程學,
.ConfigureAwait(false)
并且正在研究解決方案。一般來說,永遠不要使用
Task<T>.Result
orTask.Wait()
,因為它們會阻塞線程并引入死鎖的風險(因為不能在阻塞的線程上運行延續回調)。僅Task<T>.Result
在您驗證任務已完成(或僅執行await task
)后使用。您應該將 傳遞給您調用的
CancellationToken
每個子方法。Async
其他挑剔:
您可以
using()
在同一縮進級別組合語句并SqlConnection.OpenAsync
在創建SqlCommand
.camelCase
參數不應該PascalCase
。對實例成員(字段、方法、屬性等)的引用應加上前綴,
this.
以便在視覺上與本地標識符區分開來。這樣做
if( this.x != null ) this.x.Foo()
并不完全安全,因為在多線程程序x
中,可以在調用和調用之間用另一個值替換。而是使用保留本地參考的操作員來防止地毯從您下方拉出(它的工作原理如下:保證是線程安全的)。if
.Foo()
?.
X lx = this.x; if( lx != null ) lx.Foo()
BindingList
是(可以說)一個 UI 組件,不應該像你的FindForLocationAsync
方法那樣從概念上的“背景”函數返回,所以我返回 aList<T>
,然后 UI 將List<T>
a 包裝在BindingList<T>
.
代碼:
private async void btnSearch_Click(object sender, EventArgs e)
{
this.gridLog.DataSource = null;
this.Cursor = Cursors.WaitCursor;
if (this.btnSearch.Text.ToLower().Contains("load"))
{
this.btnSearch.Text = "Cancel";
this.btnSearch.ForeColor = Color.White;
this.btnSearch.BackColor = Color.Red;
//get params to pass
/* snip */
this.cancellationTokenSource = new CancellationTokenSource();
List<DocLog> list = await DocLog.FindForLocationAsync(docType, subType, days, currLocation.ID, cancellationTokenSource.Token);
gridLog.DataSource = new BindingList<DocLog>( list );
this.btnSearch.Text = "Load Data...";
this.btnSearch.ForeColor = Color.Black;
this.btnSearch.BackColor = Color.FromArgb(225, 225, 225);
}
else
{
CancelSearch();
this.btnSearch.Text = "Load Data...";
this.btnSearch.ForeColor = Color.Black;
this.btnSearch.BackColor = Color.FromArgb(225, 225, 225);
}
this.Cursor = Cursors.Default;
}
private void CancelSearch()
{
this.cancellationTokenSource?.Cancel();
}
public async static Task<List<DocLog>> FindForLocationAsync(string DocType, string SubType, int? LastXDays, Guid LocationID, CancellationToken cancellationToken)
{
List<DocLog> dll = new List<DocLog>();
using (SqlConnection sqlConnection = new SqlConnection(Helper.GetConnectionString()))
using (SqlCommand sqlCommand = sqlConnection.CreateCommand())
{
await sqlConnection.OpenAsync(cancellationToken).ConfigureAwait(false);
sqlCommand.CommandText = (LastXDays == null) ? "DocLogGetAllForLocation" : "DocLogGetAllForLocationLastXDays";
sqlCommand.CommandType = System.Data.CommandType.StoredProcedure;
sqlCommand.Parameters.Add("@DocType", SqlDbType.NVarChar, 30).Value = DocType.Trim();
sqlCommand.Parameters.Add("@SubType", SqlDbType.NVarChar, 30).Value = SubType.Trim();
sqlCommand.Parameters.Add("@LocationID", SqlDbType.UniqueIdentifier).Value = LocationID;
if (LastXDays != null) { sqlCommand.Parameters.Add("@NumberOfDays", SqlDbType.Int).Value = LastXDays; }
using( SqlDataReader sqlDataReader = await sqlCommand.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false) )
{
while (await sqlDataReader.ReadAsync(cancellationToken).ConfigureAwait(false))
{
if (cancellationToken.IsCancellationRequested) break;
DocLog dl = readData(sqlDataReader);
dll.Add(dl);
}
}
}
return dll;
}
- 1 回答
- 0 關注
- 150 瀏覽
添加回答
舉報