【发布时间】:2016-04-24 12:52:51
【问题描述】:
我对有关异步事件的一些最佳实践有一些疑问。更确切地说,将 async 修饰符分配给 void 方法(触发 EventHandler)
我的应用应该在后台进行一些测试,并在我完成执行后将结果上传到我的数据库。
在问这个问题之前,我已经查看了here,但我仍然觉得我做错了什么。
根据我的测试,当我调用事件处理程序时,没有明显的理由(对于我的具体情况)应用async 修饰符,因为将async 修饰符指定为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();
}
}
【问题讨论】:
标签: c# tsql events asynchronous event-handling