2016-05-13 100 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'方法。那么我认为抛出异常是最好的方法。 –