2016-05-13 103 views
1

我有一個方法在我的xamarin應用程序中從服務器獲取一些數據,並且我需要該方法在HTTP請求成功時返回數據,或者如果服務器返回一個「系統錯誤」字符串錯誤或「Internet連接錯誤」字符串(如果沒有連接)。返回多種類型

我想知道如何設置返回類型返回其中之一。我知道Tuple可以返回多個。但我相信它,而不是兩者。

我的代碼

public async Task<List<AllReportVM>> GetAllReports(string token, string username) 
    { 
     var httpClient = GetHttpClient(); 
     if (CrossConnectivity.Current.IsConnected) { 
      var response = await httpClient.GetAsync ("getdashboardreports.ashx").ConfigureAwait (false); 

      if (response.IsSuccessStatusCode) { 
       var content = response.Content; 

       string jsonString = await content.ReadAsStringAsync().ConfigureAwait (false); 

       return JsonConvert.DeserializeObject<List<AllReportVM>> (jsonString); 
      } else { 
       return "SystemError"; 
      } 
     } else { 
      return "Internet Connectivity Error"; 

     } 
    } 
+0

你用泛型類型嘗試過嗎 –

+0

不,你不能那樣做。當客戶說'ServerData data = await GetAllReports();'時,編譯器必須知道'ServerData'是正確的返回類型。編譯器無法知道請求在運行時是成功還是失敗!如果我是你,我會創建一個Response類,其中包含返回的所有信息:成功布爾值,ErrorMessage字符串,結果ServerData。如果沒有錯誤等,只需將ErrorMessage留空即可。*編輯*或拋出異常,當然。 – Blorgbeard

回答

4

您要求的內容實際上是discriminated union。 C#本質上並不是真的有這樣的東西。有幾種方法可以解決這個問題。首先,考慮一下我所說的嘗試輸入/輸出模式:

public bool GetAllResults(string token, string username, out List<AllReportVM> results); 

這是正常的比較簡單的方法,但它實際上並沒有給你錯誤消息(至少給它通常執行的方式)和out參數不適用於async方法。所以我們可以排除這一點。

第二個選項是throw an exception上的錯誤,這就是我想在90%的情況下,推薦:

public async Task<List<AllReportVM>> GetAllReports(string token, string username) 
{ 
    var httpClient = GetHttpClient(); 
    if (CrossConnectivity.Current.IsConnected) { 
     var response = await httpClient.GetAsync ("getdashboardreports.ashx").ConfigureAwait (false); 

     if (response.IsSuccessStatusCode) { 
      var content = response.Content; 

      string jsonString = await content.ReadAsStringAsync().ConfigureAwait (false); 

      return JsonConvert.DeserializeObject<List<AllReportVM>> (jsonString); 
     } else { 
      throw new RequestException("SystemError"); 
     } 
    } else { 
     throw new RequestException("Internet Connectivity Error"); 
    } 
} 

,並呼籲這一點,你不得不使用:

try 
{ 
    var list = await obj.GetAllReports(token, username); 
    ... 
} 
catch (RequestException ex) 
{ 
    Console.WriteLine(ex.Message); 
} 

這是一個非常穩固,完善的模式。事實上,您可能應該已經對可能在應用程序中發生的各種其他異常使用異常處理。但是,它確實有一些性能影響,您應該避免爲簡單控制流程使用異常。對於需要提出大量請求並希望有效處理失敗的應用程序(例如批處理),這可能不是一種選擇。當我遇到在過去這樣的情況下,我找到了實現自定義類是有用的,例如:

public class RequestResult<T> 
{ 
    public bool Success { get; } 
    public T Result { get; } 
    public string ErrorMessage { get; } 

    private RequestResult(bool success, T result, string errorMessage) 
    { 
     this.Success = success; 
     this.Result = result; 
     this.ErrorMessage = errorMessage; 
    } 

    public static RequestResult<T> Success(T result) 
    { 
     return new RequestResult<T>(true, result, null); 
    } 

    public static RequestResult<T> Failure(string errorMessage) 
    { 
     return new RequestResult<T>(false, default(T), errorMessage); 
    } 
} 

public async Task<RequestResult<List<AllReportVM>>> GetAllReports(string token, string username) 
{ 
    var httpClient = GetHttpClient(); 
    if (CrossConnectivity.Current.IsConnected) { 
     var response = await httpClient.GetAsync ("getdashboardreports.ashx").ConfigureAwait (false); 

     if (response.IsSuccessStatusCode) { 
      var content = response.Content; 

      string jsonString = await content.ReadAsStringAsync().ConfigureAwait (false); 

      var result = JsonConvert.DeserializeObject<List<AllReportVM>> (jsonString); 
      return RequestResult.Success(result); 
     } else { 
      return RequestResult.Failure("SystemError"); 
     } 
    } else { 
     return RequestResult.Failure("Internet Connectivity Error"); 
    } 
} 
0

如果不是成功的回報以外唯一的返回類型的錯誤比你應該拋出一個異常。如果你有一個特定的異常故事,你應該創建一個從Exception類繼承並拋出的類。如果存在描述您預期問題的異常,那麼您應該選擇那個。調用方法可以根據需要捕獲並處理它。

0

看着你的代碼,你可能想要拋出異常,主要是因爲你正在返回的兩個字符串似乎都指示出現異常。

還問自己「這個方法何時返回,我將如何處理輸出?」如果你不知道類型,你可以像if(result是字符串)那樣做,但是你想用它代替嗎?相反,處理異常不是更容易嗎?

如果你真的需要這樣做,你可以返回任務<對象>,你只需要檢查來自調用者的結果的類型,當你這樣做。例如:

var result = await GetAllReports(token, username) 
if (result is string) 
{ 
    //Do Something 
} 
if(result is List<AllReportVM>) 
{ 
    //Do Something 
} 

public async Task<object> GetAllReports(string token, string username) 
{ 
    var httpClient = GetHttpClient(); 
    if (CrossConnectivity.Current.IsConnected) { 
     var response = await httpClient.GetAsync ("getdashboardreports.ashx").ConfigureAwait (false); 

     if (response.IsSuccessStatusCode) { 
      var content = response.Content; 

      string jsonString = await content.ReadAsStringAsync().ConfigureAwait (false); 

      return JsonConvert.DeserializeObject<List<AllReportVM>> (jsonString); 
     } else { 
      return "SystemError"; 
     } 
    } else { 
     return "Internet Connectivity Error"; 

    } 
} 
1

我的第一選擇將是拋出一個異常錯誤的情況。

public async Task<List<AllReportVM>> GetAllReports(string token, string username) 
{ 
    var httpClient = GetHttpClient(); 
    if (CrossConnectivity.Current.IsConnected) { 
     var response = await httpClient.GetAsync ("getdashboardreports.ashx").ConfigureAwait (false); 

     if (response.IsSuccessStatusCode) { 
      var content = response.Content; 

      string jsonString = await content.ReadAsStringAsync().ConfigureAwait (false); 

      return JsonConvert.DeserializeObject<List<AllReportVM>> (jsonString); 
     } else { 
      throw new Exception("SystemError"); 
     } 
    } else { 
     throw new Exception("Internet Connectivity Error"); 

    } 
} 

這將需要調用者捕捉異常,但你只需要一個單一的返回路徑。

我的第二選擇是添加一個out參數來採取異常原因。注意:這種方法不適用於異步方法。

public Task<List<AllReportVM>> GetAllReports(string token, string username, out string error) 
{ 
    var httpClient = GetHttpClient(); 
    if (CrossConnectivity.Current.IsConnected) { 
     var response = await httpClient.GetAsync ("getdashboardreports.ashx").ConfigureAwait (false); 

     if (response.IsSuccessStatusCode) { 
      var content = response.Content; 

      string jsonString = await content.ReadAsStringAsync().ConfigureAwait (false); 

      error = null; 
      return JsonConvert.DeserializeObject<List<AllReportVM>> (jsonString); 
     } else { 
      error = "SystemError"; 
      return null; 
     } 
    } else { 
     error = "Internet Connectivity Error"; 
     return null; 
    } 
} 

如果這是不可接受的,你可以考慮將tuple的一半返回爲null。

+0

你可以在'async'方法中使用'out'參數。 –

+0

我忘了你不能使用'out'參數來實現'async'方法。那麼我認爲拋出異常是最好的方法。 –