سؤال

How can I get the HttpGet function below to populate all of the responses (denoted by #2)? I cannot seem to declare a collection of the appropriate type to handle adding each response. Everything I've tried so far has given a compiler error:

'Cannot convert expression type null to return type T`.

C#/ASP.NET/MVC 5.1/.NET 4.5

public async Task<IList<T>> Query<T>(string query)
{
    var response = await _serviceHttpClient.HttpGet<IList<T>>(string.Format("query?q={0}", query), "records");
    return response;
}

public async Task<T> HttpGet<T>(string urlSuffix, string nodeName)
{
    // #1 var list = ???
    var r = new QueryResult<T>();
    do
    {
        r = await HttpGetInternal<T>(urlSuffix, nodeName);

        // #2 list = r.Records
    } while (!string.IsNullOrEmpty(r.NextRecordsUrl));

    return // #3 list;
}

private async Task<QueryResult<T>> HttpGetInternal<T>(string urlSuffix, string nodeName)
{
    var url = Common.FormatUrl(urlSuffix, _instanceUrl, _apiVersion);

    var request = new HttpRequestMessage()
    {
        RequestUri = new Uri(url),
        Method = HttpMethod.Get
    };

    request.Headers.Add("Authorization", "Bearer " + _accessToken);

    var responseMessage = await _httpClient.SendAsync(request);
    var response = await responseMessage.Content.ReadAsStringAsync();

    if (responseMessage.IsSuccessStatusCode)
    {
        var jObject = JObject.Parse(response);
        var jToken = jObject.GetValue(nodeName);
        var res = JsonConvert.DeserializeObject<T>(jToken.ToString());

        var r = new QueryResult<T>()
        {
            NextRecordsUrl = jObject.GetValue("nextRecordsUrl").ToString(),
            Records = res
        };

        return r;
    }

    var errorResponse = JsonConvert.DeserializeObject<ErrorResponses>(response);
    throw new ForceException(errorResponse[0].errorCode, errorResponse[0].message);
} 

public class QueryResult<T>
{
    public int TotalSize { get; set; }
    public bool Done { get; set; }
    public string NextRecordsUrl { get; set; }
    public T Records { get; set; }
}
هل كانت مفيدة؟

المحلول

I would change the signature to return IList<T> the same as the method that is calling it since there isn't an easy way to create something that implements the interface specified by the generic. Another alternative would be to call it with a concrete type, say List<T>, which implements the return interface of the caller, but I think the other way is cleaner.

Since r.Records is of type T it should be able to be added to the List<T>. List<T> implements IList<T> and thus satisfies the return type.

public async Task<IList<T>> Query<T>(string query)
{
    var response = await _serviceHttpClient.HttpGet<T>(string.Format("query?q={0}", query), "records");
    return response;
}

public async Task<IList<T>> HttpGet<T>(string urlSuffix, string nodeName)
{
    var list = new List<T>();

    do
    {
        var r = await HttpGetInternal<T>(urlSuffix, nodeName);

        list.Add(r.Records);
    }
    while (!string.IsNullOrEmpty(r.NextRecordsUrl));

    return list;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top