2016-04-24 69 views
1

我对于有关异步事件的一些最佳实践有一些疑问。更确切地涉及到分配async修改为void方法(即触发EventHandler关于C#最佳实践混淆的异步事件

我的应用程序应该工作做的背景,当我完成了执行上传我的结果我的数据库一些测试。

在问这个问题之前,我看过here,但我仍然觉得我做错了什么。

从我测试过没有明显的原因(我的具体情况)申请时,我调用事件处理程序,因为指定async修饰符subscriber's基本方法,它会“回拨”的async修改当遇到第一个await恢复程序执行,直到等待的动作完成,按照我想要的完美工作。

当我开始向无效方法(WorkerClass)应用(1'st方法)async修改器时,我怀疑是否即使它是事件处理程序,我是否在做错误?

我已经做了以下测试: 取得了存储过程,而延缓它的运行了大约一分钟

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 

这是我的第1'的做法:

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(); 
      } 
     } 

回答

3

当我开始向无效方法(WorkerClass)应用异步修改器(1'st方法)时(即使它是事件处理程序),我是否会错误地执行该操作?

不,你这样做是正确的,你不应该有任何疑问。 你应该避免使用async void,除非它是一个事件处理程序。这是使用async void的唯一可接受的地方。

Async/Await - Best Practices in Asynchronous Programming - 如果您对有关异步编程的更多最佳实践感兴趣,您应该阅读本文。