2009-09-09 46 views
1

我想讓我的腦袋圍繞使用Action委託類型用於在第三方COM DLL中調用方法掛起時強制超時。經過大量搜索後,我發現我可以使用Action <>或Func <>並根據所調用的方法是否返回參數傳遞最多4個通用參數。使用參數調用泛型函數的實現超時

對於這個實例,我想調用一個返回void和2個參數的一系列方法的超時。接下來是我放在一起的代碼,但我無法確定如何正確編碼BeginInvoke,我被提示放置「T arg1」和「T arg2」,但是當我輸入param1或param2時VS2008告訴我這些值是不確定的。

下面是代碼,因爲它是迄今:

static void CallAndWait(Action<T, T> action, int timeout) 
{ 
    Thread subThread = null; 
    Action<T, T> wrappedAction = (param1, param2) => 
    { 
     subThread = Thread.CurrentThread; 
     action(param1, param2); 
    }; 

    IAsyncResult result = wrappedAction.BeginInvoke(param1, param2, null, null); 
    if (((timeout != -1) && !result.IsCompleted) && 
    (!result.AsyncWaitHandle.WaitOne(timeout, false) || !result.IsCompleted)) 
    { 
     if (subThread != null) 
     { 
      subThread.Abort(); 
     } 

     //TODO: close external resource. 

     throw new TimeoutException(); 
    } 
    else 
    { 
     action.EndInvoke(result); 
    } 
} 

任何想法,對什麼是錯在這裏將不勝感激。

下面是基於對輸入

由於第一評論迄今重新編輯的代碼。以下編譯。在調用它的時候,我似乎無法得到正確的語法。

public static void CallAndWait<T1, T2>(Action<T1, T2> action, int timeout) 
{ 
    Thread subThread = null; 
    T1 param1 = default(T1); 
    T2 param2 = default(T2); 

    Action<T1, T2> wrappedAction = (p1, p2) => 
    { 
     subThread = Thread.CurrentThread; 
     action(param1, param2); 
    }; 

    IAsyncResult result = wrappedAction.BeginInvoke(param1, param2, null, null); 
    if (((timeout != -1) && !result.IsCompleted) && 
    (!result.AsyncWaitHandle.WaitOne(timeout, false) || !result.IsCompleted)) 
    { 
     if (subThread != null) 
     { 
      subThread.Abort(); 
     } 

     //TODO: close external resource. 

     throw new TimeoutException(); 
    } 
    else 
    { 
     action.EndInvoke(result); 
    } 
} 

我試圖通過調用下面的方法用它來測試這一點:

public void LongTimeProcess(int a, string b) 
{ 
    Thread.Sleep(a); 
} 

但下面的代碼是不正確的:

Action<int, string> action = (s1, s2) => LongTimeProcess(s1, s2); 
    CallAndWait<int, string>(action(1500, "hello"), 500); 

更新代碼 我已發佈代碼供將來由論壇用戶參考。下面的代碼似乎工作。 唯一需要檢查的是當我們的「action.EndInvoke(result)」結果與動作沒有關聯時,我的單元測試會導致在第二次調用例程的同一個函數時引發異常。這可能是因爲我的LongProcess只是一個Thread.sleep,在這種情況下,這意味着我的第二次調用沒有中止。

public static void CallAndWait<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2, int timeout) 

    { 
     Thread subThread = null; 
     Action<T1, T2> wrappedAction = (p1, p2) => 
     { 
      subThread = Thread.CurrentThread; 
      action(arg1, arg2); 
     }; 

     IAsyncResult result = wrappedAction.BeginInvoke(arg1, arg2, null, null); 
     if (((timeout != -1) && !result.IsCompleted) && 
     (!result.AsyncWaitHandle.WaitOne(timeout, false) || !result.IsCompleted)) 
     { 
      if (subThread != null) 
      { 
       subThread.Abort(); 
      } 

      //TODO: close external resource. 

      throw new TimeoutException(); 
     } 
     else 
     { 
      action.EndInvoke(result); 
     } 
    } 
+0

我發現你的錯誤,並更新了我的答案。 –

+0

看到它:http://stackoverflow.com/questions/4238345/asynchronously-wait-for-taskt-to-complete-with-timeout – 2012-08-13 12:58:35

回答

1

起初它也許應該

static void CallAndWait<T>(Action<T, T> action, int timeout) 

,而不是

static void CallAndWait(Action<T, T> action, int timeout) 

,如果參數有不同的類型,甚至以下。

static void CallAndWait<T1, T2>(Action<T1, T2> action, int timeout) 

但我不認爲這是全部。要再看一遍。

UPDATE

現在我可以看到你的問題......你所呼叫的動作,當你試圖調用CallAndWait()。通話必須如下

CallWithTimeout.CallAndWait(action, 1500, "hello", 500); 

而不是您的通話。

CallWithTimeout.CallAndWait<int, string>(action(1500, "hello"), 500); 

所以,你必須在方法簽名從

void CallAndWait<T1, T2>(Action<T1, T2> action, int timeout) 

改變

void CallAndWait<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2, int timeout) 

修改身體一點,你應該做的。

+0

啊,好吧。這是有道理的,並給我一些進一步的看法。 – ChrisBD

+0

謝謝你的工作。 – ChrisBD