2016-04-24 7 views
1

Ich habe Zweifel bezüglich einiger Best Practices bezüglich der asynchronen Ereignisse. Genauer gesagt im Zusammenhang den async Modifikator auf eine void-Methode zur Zuordnung (das löst ein EventHandler)Async-Ereignis bei C# Best Practice Confusion

Meine App funktionieren sollte einige Tests auf dem Hintergrund zu tun, und wenn ich die Ausführung beenden, um meine Ergebnisse zu meinem Db hochladen.

Bevor ich die Frage stelle, habe ich einen Blick über here geworfen, aber ich habe immer noch das Gefühl, dass ich etwas falsch mache.

Von dem, was ich getestet habe es keinen ersichtlichen Grund (für meinen speziellen Fall) ist die async Modifikator anwenden, wenn ich den Event-Handler nenne, weil die Angabe der async Modifikator subscriber's zugrunde liegenden Methoden werden es ‚Dial-back‘ wenn ich die erste await wiederfinde die Programmausführung, bis die erwartete Aktion beendet ist, funktioniert perfekt wie ich wollte.

Meine Zweifel kam, als ich begann die Anwendung (1'st Ansatz), um den async Modifikator auf ein void-Methode (die WorkerClass), obwohl es der Event-Handler ist, bin ich es falsch gemacht?

Ich habe den folgenden Test durchgeführt: eine gespeicherte Prozedur hergestellt, das es ist die Ausführung für etwa eine Minute verzögert

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 

Das ist mein 1'st Ansatz ist:

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

Mein zweiter Ansatz ist:

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

Antwort

3

Meine Zweifel kamen, als ich anfing, den Async-Modifizierer auf eine void-Methode (die WorkerClass) anzuwenden, obwohl es der Event-Handler ist, mache ich das falsch?

Nein, Sie tun es richtig und Sie sollten keine Zweifel haben. Sie sollten Async void vermeiden, es sei denn, es handelt sich um einen Event-Handler. Das ist der einzige akzeptable Ort, um Async void zu verwenden.

Async/Await - Best Practices in Asynchronous Programming - Sie sollten diesen Artikel lesen, wenn Sie sich für weitere Best Practices zur asynchronen Programmierung interessieren.