2013-04-08 66 views
1

我有一個調用Bing Api的方法。製作異步方法

IEnumerable<WebResult> Search(string query) 

我想使這個異步,以便如果我打了很多電話,它們中的每一個都是獨立的。所以,以下的建議here我改變了簽名

async Task<IEnumerable<WebResult>> SearchAsynch(string query) 

但我得到警告

This async method lacks 'await' operators and will run synchronously... 

我想整個方法要非同步(至少這是我怎麼想它應該工作)。我怎麼做?這裏是我的代碼

public async Task<IEnumerable<WebResult>> SearchAsynch(string query) 
     { 
      if (query == null) 
      { 
       throw new ArgumentNullException("query cannot be null"); 
      } 

      DataServiceQuery<WebResult> webQuery = _bingContainer.Web(query, null, null, null, null, null, null, null); 
      IEnumerable<WebResult> webResults = webQuery.Execute(); 
      return webResults; 
     } 

問題是,我不知道該代碼中要等待什麼。

+1

也許[this](http://msdn.microsoft.com/en-us/library/dd756367.aspx)文章會有幫助嗎? – nkvu 2013-04-08 20:47:50

+0

+1的幫助提示。謝謝。 – 2013-04-08 20:50:42

回答

6

async關鍵字不會創建新的異步操作,它只是一種更簡單的方法,可以更輕鬆地配置已存在的任務(即異步操作)的延續。

在這種情況下,DataServiceQuery類已經提供了一種異步執行查詢的方法。不幸的是它使用舊的異步模式,而不是新Task基於模型,所以你需要使用Task.Factory.FromAsync翻譯它:

public Task<IEnumerable<WebResult>> SearchAsynch(string query) 
{ 
    DataServiceQuery<WebResult> webQuery = _bingContainer.Web(query, null, null, null, null, null, null, null); 

    return Task.Factory.FromAsync(webQuery.BeginExecute(null, null) 
     , asyncResult => webQuery.EndExecute(asyncResult))); 

} 

在這種特殊情況下,因爲你不需要做其他比創建任務什麼你根本不需要asyncawait,你可以返回構建的任務。如果你想要做的東西,你得到的結果可以轉而await任務後:

public async Task<IEnumerable<WebResult>> SearchAsynch(string query) 
{ 
    DataServiceQuery<WebResult> webQuery = _bingContainer.Web(query, null, null, null, null, null, null, null); 
    var results = await Task.Factory.FromAsync(webQuery.BeginExecute(null, null) 
      , asyncResult=> webQuery.EndExecute(asyncResult)); 
    Console.WriteLine("Hi there"); 
    return results; 
} 
+0

使用此方法時,我是否在調用SearchAsync時使用async關鍵字? – 2013-04-08 21:50:27

+0

@SachinKainth您可以使用它或不使用它;它完全取決於你是否想要,或者在上下文中是否合適。你當然不會*擁有*,但你可以。 – Servy 2013-04-09 02:56:57

-1

該警告只是告訴你,無論你打電話給SearchAsynch它需要等待它之前。

var result = await SearchAsynch(query);

然而,SearchAsynch未正確執行正如其他人說。

+0

那麼,沒有這不工作,因爲我得到了錯誤「等待操作符只能用於方法或用異步修飾符標記的lambda」 – 2013-04-08 20:52:20

+1

他需要完成正確實現'SearchAsynch'(這就是這個問題是什麼在他能夠「等待」之前尋求幫助)。 – Servy 2013-04-08 21:17:44

+0

警告明確指出,他正在做的事情將同步運行,直到使用await關鍵字。因此,即使他確實正確地執行了它,並且await關鍵字丟失了,它也不會是異步的。幾乎不值得讚揚。 – 2013-04-08 21:24:01

0

每MSDN

通常,由異步關鍵字改性的方法包含至少一個 等待表達 或語句。該方法同步運行,直到它達到第一個等待表達式 ,此時它被掛起,直到等待完成的任務完成。同時, 控制權返回給方法的調用者。如果該方法不包含等待 表達式或語句,則它將同步執行。編譯器警告會提醒您 任何不包含等待的異步方法,因爲該情況可能表示出現錯誤。 有關更多信息,請參閱編譯器警告(1級)CS4014。

編輯:我想我會加入到這個,但它已經在這篇文章的評論部分。標記爲async的方法實際上不運行異步,直到它遇到await關鍵字。

+0

謝謝,我知道,但我的問題是,我不知道要在我的代碼中等待什麼。 – 2013-04-08 20:52:56

+0

@SachinKainth await關鍵字應該應用於您的webQuery.Execute()行,然後返回數據。 await關鍵字是異步操作的實際開始。在此之前,它是同步執行的。 – Justin 2013-04-08 21:04:05

4

我對Bing API並不十分熟悉,但是如果API不包含異步方法,則可以通過將調用包裝在已啓動的Task中來創建一個異步。 async修飾符不會使您的方法自動異步,它只允許await裏面的其他異步方法。

所以,在你的情況下,它很可能是最簡單的:

public Task<IEnumerable<WebResult>> SearchAsync(string query) 
    { 
     if (query == null) 
     { 
      throw new ArgumentNullException("query cannot be null"); 
     } 

     return Task.Run(() => 
      { 
       DataServiceQuery<WebResult> webQuery = _bingContainer.Web(query, null, null, null, null, null, null, null); 
       return webQuery.Execute(); 
      } 
    } 

然後你就可以await在其他方法這種方法標記爲async

var result = await SearchAsync("yourQuery"); 

如果必應API有異步方法對Begin/End,您可以使用Task.Factory.FromAsync從異步方法對創建任務。 Servy的答案在那裏更詳細。

+0

問題是我將單元測試此方法,並且這些方法未標記爲異步 – 2013-04-08 20:57:54

+1

如果您正在進行單元測試並且不想使用同步上下文,則可以執行阻止等待。 'var taskResult = SearchAsync(「query」); Task.Wait(taskResult);'。然後你可以通過'taskResult.Result'訪問結果。這*應該可能*工作... – 2013-04-08 20:59:35

+0

另外我得到另一個錯誤說:「因爲這是一個異步方法,返回表達式必須是類型'System.Collections.Generic.IEnumerable '而不是'任務< System.Collections.Generic.IEnumerable >'「 – 2013-04-08 21:00:31

0

這是一個獨立的項目中使用異步的例子。

private async void button2_Click(object sender, EventArgs e) 
{ 
    DataTable dtMessages = await getMessages2(string sqlConn2, nMessage); 
} 
public async Task<DataTable> getMessages2(string sqlConn, int n) 
{ 
    //create your query and command 
    var o = await cmd2.ExecuteReaderAsync(); 
    DataTable dtMessages = o; 
    return dtMessages; 
}