2013-03-23 19 views
14

我有一個異步方法具有以下簽名:BeginXXX for FromAsync中的參數太多?

IAsyncResult BeginGetMyNumber(string foo, string bar, string bat, int bam, AsyncCallback callback, object state) 

我希望它使用Factory.FromAsync這樣執行:

var result = Task<int>.Factory.FromAsync(
       instance.BeginGetMyNumber, 
       instance.EndGetMyNumber, 
       "foo", 
       "bar", 
       "bat", 
       100, /*bam*/ 
       null); 

,但我得到了以下錯誤:

Argument 1: cannot convert from 'method group' to 'System.Func'

似乎沒有合適的重載FromAsync方法http://msdn.microsoft.com/en-us/library/system.threading.tasks.taskfactory.fromasync.aspx,它只支持最多5個參數(包括回調和狀態) BeginXXX方法。

除了重構BeginXXX方法來獲取一個對象而不是六個參數之外,有沒有一種方法可以使用FromAsync來執行它?

回答

7

實際上似乎我可以使用重載方法Factory.FromAsync(其採用IAsyncResult對象作爲第一個參數和回調方法作爲第二:

result = Task<string>.Factory.FromAsync(
       instance.BeginGetMyNumber("foo", "bar", "bat", 1, null, null), 
       instance.EndGetMyNumber); 
+4

有了這個重載,'FromAsync'沒有機會將回調傳遞給'BeginGetMyNumber'方法 - 您已經傳遞null。 相反,這個重載將在操作完成時使用'IAsyncResult.WaitHandle'來通知。這效率較低 - 有關詳細信息,請參閱http://blogs.msdn.com/b/pfxteam/archive/2012/02/06/10264610.aspx。 – Daniel

+0

它適用於四個參數,但我有五個參數相同不適用於我的情況。我該怎麼辦 ? –

3

是的,基本上,你已經用完了論據。 :(

FromAsync方法只需要最多三個傳遞到最異步調用的參數,全面闡述了像這樣:

var result = Task<int> 
    .Factory 
    .FromAsync<string,string,string>(
     BeginGetMyNumber, 
     EndGetMyNumber, 
     "foo", 
     "bar", 
     "bat", 
     null); 

,如果你有這將工作:

IAsyncResult BeginGetMyNumber(
    string foo, 
    string bar, 
    string bat, 
    AsyncCallback callback, 
    object state) 
{ 
} 

但ye've了一個太多

哦,得到的東西,可能會幫助 - 你將要清理它,這是極其扔在一起!

public static class Ext 
{ 
    public static Task<TResult> FromAsync<TArg1, TArg2, TArg3, TArg4, TResult>(
     this TaskFactory<TResult> factory, 
     Func<TArg1,TArg2,TArg3,TArg4,AsyncCallback, object, IAsyncResult> beginMethod, 
     Func<IAsyncResult, TResult> endMethod, 
     TArg1 arg1, 
     TArg2 arg2, 
     TArg3 arg3, 
     TArg4 arg4, 
     object state, 
     TaskCreationOptions creationOptions = TaskCreationOptions.None, 
     TaskScheduler scheduler = null) 
    { 
     scheduler = scheduler ?? TaskScheduler.Current; 
     AsyncCallback callback = null; 
     if (beginMethod == null) 
     { 
      throw new ArgumentNullException("beginMethod"); 
     } 
     if (endMethod == null) 
     { 
      throw new ArgumentNullException("endMethod"); 
     } 
     TaskCompletionSource<TResult> tcs = 
      new TaskCompletionSource<TResult>(state, creationOptions); 
     try 
     { 
      if (callback == null) 
      { 
       callback = delegate (IAsyncResult iar) 
       { 
        tcs.TrySetResult(endMethod(iar)); 
       }; 
      } 
      beginMethod(arg1, arg2, arg3, arg4, callback, state); 
     } 
     catch 
     { 
      tcs.TrySetResult(default(TResult)); 
      throw; 
     } 
     return tcs.Task; 
    } 
} 
+0

這很酷 - 但它看起來像我可以使用不同的重載方法。 –

8
result = Task<string>.Factory.FromAsync(
    (callback, state) => instance.BeginGetMyNumber("foo", "bar", "bat", 1, callback, state), 
    instance.EndGetMyNumber); 

這技術(部分函數應用程序)適用於任意數量的輸入參數的開始方法。

+0

FromAsync的這個重載需要狀態作爲第三個參數。除此之外,爲我工作。 – Royston46

+0

像魅力一樣工作。 OP應該自己接受這個答案。 –

+1

好吧,這已經過了一年,我已經接受了我自己的答案。該死的你,熵! –