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 关注
- 113 浏览
添加回答
举报