2016-09-21 66 views
1

我正在研究C#Hue應用程序,我正在創建api調用自己的學習體驗。由於Hue由很多網絡調用組成,我想爲每個創建的同步方法提供一個異步方法。我寫了一些代碼行,並認爲「這不可能是那麼容易」,所以現在我在這裏,想問問這是否是實現異步函數的好方法?還有我的代碼的任何其他優化表示讚賞。異步代碼很容易嗎?

using System.IO; 
using System.Net; 
using System.Threading.Tasks; 
using Newtonsoft.Json; 

namespace SharpHue 
{ 
    public class HueUtilities 
    { 
     const string DISCOVERY_URI = "http://www.meethue.com/api/nupnp"; 

     public struct DiscoveryElement 
     { 
      [JsonProperty("id")] 
      public string ID; 
      [JsonProperty("internalipaddress")] 
      public string Address; 
     } 

     public static DiscoveryElement[] DiscoverBridges() 
     { 
      string data = "[]"; 
      var request = WebRequest.CreateHttp(DISCOVERY_URI); 
      try 
      { 
       var response = request.GetResponse(); 
       using (var streamReader = new StreamReader(response.GetResponseStream())) 
       { 
        data = streamReader.ReadToEnd(); 
        streamReader.Close(); 
        response.Close(); 
       } 
       return JsonConvert.DeserializeObject<DiscoveryElement[]>(data); 
      } 
      catch (Exception ex) 
      { 
       throw ex; 
      } 
     } 

     public static async Task<DiscoveryElement[]> DiscoverBridgesAsync() 
     { 
      return await Task.Run(() => DiscoverBridges()); 
     } 
    } 
} 
+0

基本上,所有的IO代碼都必須重複。這對生產力和維護造成了嚴重的負擔。所以想想來電者是否需要/想要這兩種風格。您也可以使用異步同步來以相當小的性價比提供同步便利包裝。 – usr

回答

0

差不多。但是,如果有真正的異步替代方案,您應該避免使用Task.Run。在你的情況這意味着HttpClient的替代WebRequest類和打電話給你這樣的代碼:

public static async Task<DiscoveryElement[]> DiscoverBridgesAsync() 
{ 
    using (var client = new HttpClient()) 
    { 
     var result = await client.GetAsync(DISCOVERY_URI); 
     return await result.Content.ReadAsAsync<DiscoveryElement[]>();  
    } 
} 

正如你可以看到有沒有更多的用於該包裹的異步調用同步調用的方法。它現在是真正的異步/等待兼容。

警告可能有一些編譯錯誤,但應該工作。

更多信息:http://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client

並請,請閱讀本:http://www.ben-morris.com/why-you-shouldnt-create-asynchronous-wrappers-with-task-run/

+0

它工作得很好:)這些方法應該並行存在 - 您應該能夠在需要時調用同步並調用異步。你會推薦重寫同步方法嗎?還是保留它? – Benedikt

+0

@Benedikt:我建議只保留異步版本,因爲這是一個異步操作。但是,如果你**必須**保持兩個異步/同步版本,並且你想避免代碼重複,那麼請查看我的[brownfield async development文章]中的「bool argument hack」(https://msdn.microsoft .COM/EN-US /雜誌/ mt238404.aspx)。 –

+0

@StephenCleary不錯的一個!將記住我的代碼以及:-) –

0

沒有async代碼是出了名的難寫,這就是爲什麼他們增加了async關鍵字。問題往往是人們不明白代碼是什麼,爲什麼使用它。此代碼

var result = await Task.FromResult(0); 

similar使用異步關鍵字不會讓這麼寫

Task.FromResult(0).ContinueWith((task)=> 
      { 
       var result = task.Result; 
      }); 

如果代碼是不Asynchronous。您的代碼是異步的,因爲Task.Run劑量,而不是異步關鍵字。像ReadStreamReadstreamAsync這樣的東西實際上可能會做兩個完全不同的事情,如file access。 因爲asp沒有UI線程,Task.Run在Asp.Net和Wpf中不會有相同的作用。此外,任務與線程無關,它們可以在單個線程上運行並在某些情況下執行。 Akavache是如何在單個線程上執行異步編程的例子。如果你不明白在後臺會做什麼,你必須使用異步進行實時操作。