返回多种类型

时间:2016-05-13 03:35:13

标签: c# function c#-4.0 xamarin

我的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";

        }
    }

4 个答案:

答案 0 :(得分:4)

你所要求的实际上是discriminated union。 C#本身并没有这样的东西。有几种方法可以解决这个问题。首先,考虑我称之为try / out模式的内容:

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");
    }
}

答案 1 :(得分: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;
    }
}

如果这是不可接受的,你可以考虑将元组的一半返回为元组为空。

答案 2 :(得分:0)

如果成功返回之外的唯一返回类型是错误,则应抛出异常。如果您有一个特定的异常故事,您应该创建一个继承自Exception类的类并抛出它。如果存在描述您预期问题的异常,那么这就是您应该选择的异常。然后,调用方法可以根据需要捕获并处理它。

答案 3 :(得分:0)

查看你的代码你可能想要抛出异常,主要是因为你返回的两个字符串似乎都表明发生了异常。

另外问问自己&#34;当这个方法返回时,我将如何处理输出?&#34;如果你不知道类型,你当然可以做if(结果是字符串)这样的事情,但是你想用你的代码乱丢?是不是更容易处理异常呢?

如果你真的需要这样做,你可以返回Task&lt; object&gt;,你只需要在调用时检查调用者的结果类型。例如:

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";

    }
}