我对与异步事件有关的一些最佳实践有一些疑问。更确切地说,将async
修饰符分配给void方法(触发EventHandler
)
我的应用程序应该在后台进行一些测试,当我完成执行以将结果上传到我的Db时。
在提出问题之前,我已经查看here,但我仍然觉得我做错了。
根据我测试的结果,在我调用事件处理程序时,没有明显的理由(针对我的具体情况)应用async
修饰符,因为将async
修饰符指定为{{ 1}}潜在的方法,它会拨回'遇到第一个subscriber's
恢复程序执行直到等待的行动结束,完全按照我的意愿工作。
当我开始将await
修饰符应用于async
修饰符到void方法(WorkerClass
)时,我的疑问来了,即使它是事件处理程序,我是做错了吗?
我做了以下测试: 制作了一个存储过程,延迟执行约一分钟
alter procedure TestStoredProcedure
@WhileValue int
as
begin
set nocount on;
begin transaction
begin try
waitfor delay '00:01';
insert into WhileResults(Value)
values
(@WhileValue)
commit tran;
end try
begin catch
raisError('Error',16,1);
rollback tran;
end catch;
return;
end
go
这是我的第一个方法:
class Program
{
static void Main(string[] args)
{
var workerClass = new WorkerClass();
var engine = new PlaybackEngine();
engine.TestFinishedEventHandler += workerClass.WorkSomething;
engine.TestRun();
}
}
class PlaybackEngine
{
public EventHandler TestFinishedEventHandler;
public void TestRun()
{
var i = 0;
while (i < 10000)
{
Console.WriteLine(i);
i++;
OnTestFinishedEventHandler(i,new EventArgs());
}
}
protected virtual void OnTestFinishedEventHandler(object sender, EventArgs args)
{
TestFinishedEventHandler?.Invoke(sender,args);
}
}
class WorkerClass
{
public async void WorkSomething(object sender, EventArgs args)
{
await UploadToDbAsync((int)sender);
}
private async Task UploadToDbAsync(int i)
{
using (var sqlConn = new SqlConnection("Data Source=EDWARD;Initial Catalog=TestDb;Integrated Security=True"))
using (var sqlCommand = new SqlCommand())
{
sqlConn.Open();
sqlCommand.Connection = sqlConn;
sqlCommand.CommandTimeout = 1000000;
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.CommandText = "dbo.TestStoredProcedure";
sqlCommand.Parameters.AddWithValue("@WhileValue", i);
await sqlCommand.ExecuteNonQueryAsync();
sqlConn.Close();
}
}
}
我的第二种方法是:
class Program
{
static void Main(string[] args)
{
var workerClass = new WorkerClass();
var engine = new PlaybackEngine();
// engine.TestFinishedEventHandler += workerClass.WorkSomething;
engine.TestFinished += workerClass.WorkSomething;
engine.TestRun();
}
}
class PlaybackEngine
{
public delegate Task TestRunEventHandler(object source, EventArgs args);
public event TestRunEventHandler TestFinished;
public void TestRun()
{
var i = 0;
while (i < 10000)
{
/* Doing some work here */
i++;
OnTestRan(i,new EventArgs());
Console.WriteLine(i);
}
}
protected virtual async void OnTestRan(object source, EventArgs args)
{
//await TestFinished?.Invoke(source, EventArgs.Empty);
if (TestFinished != null)
await TestFinished(source, new EventArgs());
}
}
class WorkerClass
{
public async Task WorkSomething(object sender, EventArgs args)
{
await UploadToDbAsync((int)sender);
}
private async Task UploadToDbAsync(int i)
{
using (var sqlConn = new SqlConnection("Data Source=EDWARD;Initial Catalog=TestDb;Integrated Security=True"))
using (var sqlCommand = new SqlCommand())
{
sqlConn.Open();
sqlCommand.Connection = sqlConn;
sqlCommand.CommandTimeout = 1000000;
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlCommand.CommandText = "dbo.TestStoredProcedure";
sqlCommand.Parameters.AddWithValue("@WhileValue", i);
await sqlCommand.ExecuteNonQueryAsync();
sqlConn.Close();
}
}
答案 0 :(得分:3)
当我开始将(as'stst方法)async修饰符应用于void方法(WorkerClass)时,我的疑问来了,即使它是事件处理程序,我做错了吗?
不,你正确地做了,你不应该有任何疑问。 您应该避免使用async void,除非它是一个事件处理程序。这是唯一可以使用async void的地方。
Async/Await - Best Practices in Asynchronous Programming - 如果您对有关异步编程的更多最佳实践感兴趣,请阅读本文。