2016-06-27 17 views
1

Ich starte einen Timer mit einer Callback-Funktion. Aber in dieser Callback-Funktion ändere/initialisiere ich ein statisches Objekt, das nach dem Start des Timers verwendet wird.Warten Sie, dass die Threading.Timer-Rückruffunktion endet

public class TimerExecute 
{ 
    // Assume that the "Dog" class exist with attribute Name initialized in the constructor 
    public static List<Dog> listDog = new List<Dog>(); 

    public void callbackFunct(String param) { 

     // code... 

     listDog.Add(new Dog("Bob")); 

     // code... 
    } 

    public void Main() { 
     // add dogs Bob each 10sec 
     Timer addbobs = new Timer((e) => callbackFunct("arg"), null, 0, 10000); 

     // return argumentoutofrange exception 
     Console.WriteLine(listDog[0].name); 
    } 
} 

Wenn ich die statische var verwende, habe ich eine Ausnahme "Argument außerhalb des Bereichs Ausnahme". Ich denke, das Problem ist, dass die Callback-Funktion ihre Ausführung nicht beendet hat und das Objekt noch nicht initialisiert wurde.

habe ich versucht, diese Lösung aber das funktioniert nicht:

// add dogs Bob each 10sec 
Timer addbobs = new Timer((e) => callbackFunct("arg"), null, 0, 10000); 
WaitHandle h = new AutoResetEvent(false); 
addbobs.Dispose(h); 
Console.WriteLine(listDog[0].name); 

Aber mit diesem, es funktioniert:

Timer addbobs = new Timer((e) => callbackFunct("arg"), null, 0, 10000); 
Thread.Sleep(2000); 
Console.WriteLine(listDog[0].name); 

Ich möchte, dass meine Callback-Funktion, bevor die nächste Anweisung ihre Ausführung beendet. Haben Sie eine Lösung für mein Problem?

Letzte Änderung: Ja, ich möchte in der Lage sein, Parameter zu callbackFunct passieren

+1

Sie sollten keine NULL-Referenzausnahme erhalten, Sie sollten wahrscheinlich eine Ausnahme außerhalb des Bereichs erhalten. Können Sie uns den genauen Wortlaut der Ausnahme nennen? –

+0

Ja, Entschuldigung, es ist eine "Ausnahme außerhalb des Bereichs" – Neyoh

+0

'neuer Timer (callbackFunct, null, 0, 10000);' kompiliert nicht. Können Sie den tatsächlich verwendeten Code posten oder Ihren Beispielcode korrigieren, damit er kompiliert werden kann? – Quantic

Antwort

1

Hier ist, was ich gefunden habe. Der Trick besteht darin, die AutoResetEvent zu übergeben, und Sie müssen Set() auf diesem Ereignis selbst aufrufen, was signalisiert, dass die Methode "abgeschlossen" ist (wirklich signalisiert es nur, dass die Methode aufgerufen wurde, ob die Methode fertig ist oder nicht). Weil es scheint, dass Sie andere Parameter benötigen, die an den Rückruf zusätzlich zu der WaitHandle gesendet werden, machte ich eine Klasse, beide zu kapseln.

 public void callbackFunct(object state) 
     { 
      var myParams = (CustomParametersWithWaitHandle)state; 
      string name = myParams.Parameter1; 
      AutoResetEvent wh = myParams.WaitHandle; 
      // code... 

      listDog.Add(new Dog(name)); 

      // code... 

      wh.Set(); // signal that this callback is done 
     } 

     public void Main() 
     { 
      // add dogs Bob each 10sec 
      AutoResetEvent wh = new AutoResetEvent(false); 
      var myCustomParams = new CustomParametersWithWaitHandle(wh, "bob", 314); 
      Timer addbobs = new Timer(new TimerCallback(callbackFunct), myCustomParams, 0, 10000); 
      wh.WaitOne(); // blocks here until `Set()` is called on the AutoResetEvent 

      Console.WriteLine(listDog[0].name); 
     } 
    } 

    public class CustomParametersWithWaitHandle 
    { 
     public AutoResetEvent WaitHandle { get; set; } 
     public string Parameter1 { get; set; } 
     public int Parameter2 { get; set; } 

     public CustomParametersWithWaitHandle(AutoResetEvent h, string parameter1, int parameter2) 
     { 
      WaitHandle = h; 
      Parameter1 = parameter1; 
      Parameter2 = parameter2; 
     } 
+0

Oh netter Trick, ich werde lieber passen Meine Parameter direkt mit Callback funktionieren wie ich. Aber ich werde das versuchen, ich halte dich in der Schleife – Neyoh

+0

Ich habe gerade über dieses Zeug gelernt, damit es falsch sein kann. Aber von dem, was ich verstehe, bedeutet das Beispiel, dass Sie die Callback-Funktion für das "AutoResetEvent" verwenden müssen, und die Parameter des Callback müssen das Ereignis akzeptieren, damit es 'event.Set()' on aufrufen kann Sie können also nicht einfach eine "Zeichenkette" als Parameter für Ihre Callback-Funktion übergeben, da sie die Ereignissignatur von "Objekt" aufnehmen muss und das Objekt das "AutoResetEvent" enthält. Also mit meiner benutzerdefinierten Klasse hat es jetzt auch eigene Parameter. – Quantic

+0

Es funktioniert, Danke – Neyoh

0

ich ziemlich sicher bin, sollten Sie Ihre TimerCallback mit new TimerCallback(callbackFunct) statt nur den Namen der Funktion werden initialisiert. Das sollte der Grund sein, warum deine Liste nicht mit Bobs gefüllt ist (ich kann nicht verstehen, wie es überhaupt kompiliert, aber ...). Wie:

Timer addbobs = new Timer(new TimerCallback(callbackFunct), null, 0, 10000); 

Die Ihre Funktion wird wie folgt aussehen:

public void callbackFunct(object state){ 
     //... 
     listDog.Add(new Dog("Bob")); 
     //... 
} 

es möglich sein könnte, es zu initialisieren, ohne eine neue Instanz, aber ich bin nicht ganz sicher ... PS: I vermute, dass das nicht der Code ist, den du verwendest, da er nicht einmal kompiliert. Achten Sie darauf, es zu aktualisieren ...

+0

"Das sollte der Grund sein, warum deine Liste nicht mit Bobs gefüllt ist" - vielleicht, vielleicht auch nicht. Sein Code wird nicht einmal kompiliert, daher ist es schwer zu sagen, ob sein Kompilierungs-Fix sein Problem tatsächlich behebt, da er anderen Code ausführen muss, der * kompiliert. – Quantic

+0

Ich denke schon, aber wie ich seine Bearbeitung jetzt sehe, fange ich an zu denken, dass seine Funktion in Ordnung ist und das Problem woanders ist, da es die Bobs nach einer Verzögerung füllt ... –