2012-02-16 73 views
0

我有一個創建定時器的循環。我有2個問題。System.threading.timer在循環中給出意想不到的結果

第一個問題是如何將一個命令作爲一個「消失和遺忘」來運行,因此我可以調用它,它將在另一個線程中自己執行,並且它將自己發回API。如果刷新屬性設置爲0,則是這種情況。

第二個是循環中的參數(check.key)在循環的下一次迭代中被替換。當委託觸發該方法時,它會傳遞替換的值,而不是原來分配的值!

在下面的例子中,值被正確賦值,但是當委託觸發時,它總是以參數「3」觸發。

詞典_mydict充滿了來自遠程API的數據。

classtocall和methodtocall不會總是相同的。它們可以被多次調用,因爲提供的關鍵字可以訪問Test類中的更多參數。 Test類中的refresh屬性定義了定時器時間。

我希望這是有道理的!

代碼(快速樣機是我真正的代碼爲大):

public class Test 
{ 
    public string ClassToCall; 
    public string MethodToCall; 
    public string UniqueKey; 
    public long Refresh; 
    // more but removed for sample 

    public Test(string MyClass, string MyMethod, string Key) 
    { 
     this.ClassToCall = MyClass; 
     this.MethodToCall = MyMethod; 
     this.UniqueKey = Key; 
    } 
} 

class runme 
{ 
    public static void runmefirst(string Key) 
    {// Does some processing based on Key 
    } 

    public static void runmesecond(string Key) 
    { // Does some processing based on Key 
    } 

    public static void runmelast(string Key) 
    { // Does some processing based on Key 
    } 
} 

class myclass 
{ 
    private static Timer[] timers; 

    static void Main() 
    { 

     Dictionary<string, Test> _mydict = new Dictionary<string, Test>(); 

     _mydict.Add("1", new Test("runme", "runmefirst", "1")); 
     _mydict.Add("2", new Test("runme", "runmesecond", "2")); 
     _mydict.Add("3", new Test("runme", "runmelast", "3")); 

     int i = 0; 

     foreach (KeyValuePair<string,Test> check in _mydict) 
     { 

      Type t = Type.GetType(check.Value.ClassToCall); 
      if (t != null) 
      { 
       MethodInfo mi = t.GetMethod(check.Value.MethodToCall); 
       if (mi != null) 
       { 
        if (check.Value.Refresh == 0) 
        { 
         mi.Invoke(null, new string[] { check.Key }); // << problem 1: need this fire and forget! 
        } 
        else 
        { 
         myclass.timers[i] = new Timer(
          delegate { mi.Invoke(null, new string[] { check.Key }); }, // << problem 2: when called, check.Key is always last value in loop 
          null, 
          i * 1000, 
          check.Value.Refresh * 5000 
         ); 
        } 
       } 
      } 
      i+=1; 
     } 
    } 
} 

感謝

+0

沒時間輸入到這一個完整的反應,但你應該看看'System.Threading.Tasks'(HTTP ://msdn.microsoft.com/en-us/library/system.threading.tasks.aspx),以'Task.Factory.StartNew(()=> {/ *你的火和忘記代碼在這裏* /}開始) ;' - 見http://msdn.microsoft.com/en-us/library/dd321439.aspx – tomfanning 2012-02-16 08:30:04

回答

0

對於定時器部分:

您還沒有表現出哪種Timer你'正在使用(有三個)。如果您使用System.Threading.TimerSystem.Timers.Timer話,我希望它已經線程池執行...


對於錯誤的值部分:

您使用的是循環:

foreach (KeyValuePair<string,Test> check in _mydict) 

,然後你在一個匿名方法捕獲check

delegate { mi.Invoke(null, new string[] { check.Key }); }, 

即捕獲變量check,並且check的值在每次迭代中發生變化。你將永遠看到最後的價值。這一個容易解決,雖然:

foreach (KeyValuePair<string,Test> check in _mydict) 
{ 
    var copy = check; 

    ... 

    // Then later... 
     delegate { mi.Invoke(null, new string[] { copy.Key }); }, 
} 

這個時候你會在每次迭代捕獲「新」局部變量和局部變量的值不會改變。

請注意,C#5中的行爲將會改變,以允許您以前的代碼在此處工作。

另一方面,您可以使用Delegate.CreateDelegate直接從MethodInfo創建一個委託,並將其傳遞給...

+0

完美。解決這個問題非常簡單。謝謝 – 2012-02-16 20:05:24

0

啓動一個新線程

System.Threading.Thread mythread = 
new System.Threading.Thread(new System.Threading.ThreadStart(MyFunction)); 
mythread .Start(); 

的函數調用

private void MyFunction() 
{ 
    if (InvokeRequired) 
    { 
     this.Invoke(new MethodInvoker(MyFunction)); 
     return; 
    } 
    //DO YOUR STUFF 
} 
相關問題