2013-04-08 81 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; 
}