【问题标题】:Casting simple generic objects铸造简单的通用对象
【发布时间】:2013-04-02 14:13:37
【问题描述】:

我创建了一个用于简化使用 HttpClient 调用的方法。它使用 HttpReponse.Content.ReadAsAsync().Result 方法从 API 获取响应。

这一切都很好。我的方法看起来像这样:

    public static T ExecuteAPIGetRequest<T>(string url, Dictionary<string, string> parameters)
    {

        HttpClient client = new HttpClient();
        //basic authentication

        var t = new object();
        string baseURL =  "myurl"; 

        //Execute request
        HttpResponseMessage response = client.GetAsync(baseURL).Result;

        if (response.IsSuccessStatusCode)
        {
            return response.Content.ReadAsAsync<T>().Result;  
        }
        else
        {
            return (T)t;
        }
    }

我的问题是,如果查询失败,它需要返回一个空类型的 T。如果它是我编写的自定义类,这很好,但它不适用于字符串或字符串 [] 等对象。有什么想法吗?

干杯

NCBL

【问题讨论】:

    标签: c# asp.net-web-api dotnet-httpclient


    【解决方案1】:

    尝试返回default(T)

    if (response.IsSuccessStatusCode)
    {
        return response.Content.ReadAsAsync<T>().Result;  
    }
    else
    {
        return default(T);
    }
    

    default 将为引用类型返回 null,并将数值 intdouble 等归零。自定义 structenum 的相应默认值。

    Daniel 好心地指出了一个问题:如果引用类型要返回 default object 而不是 null,则应定义通用约束 new T()。现在您可以使用对无参数构造函数的调用来实例化T 类型的对象。完整方法如下:

    public static T ExecuteAPIGetRequest<T>(string url, 
                                            Dictionary<string, string> parameters)
                                                                       where T : new()
    {
    
        HttpClient client = new HttpClient();
    
        //basic authentication
    
        string baseURL =  "myurl"; 
    
        HttpResponseMessage response = client.GetAsync(baseURL).Result;
    
        if (response.IsSuccessStatusCode)
        {
            return response.Content.ReadAsAsync<T>().Result;  
        }
        else
        {
            return new T(); //returns an instance, not null
        }
    }
    

    现在您将返回引用类型的默认对象,而不是 null。开放类型T只能带类型,默认有构造函数(不带参数)

    【讨论】:

    • 请注意:如果T 很可能是引用类型,这将是null。如果要返回默认的 instance,则需要将 new 约束添加到 Treturn new T();
    • @DanielHilgarth 也许我遗漏了一些东西,但default(T) 为原语和自定义结构返回正确的值。我刚刚测试了double 和自定义结构。你不需要指定泛型约束,struct 总是有无参数构造函数
    • @IlyaIvanov:我不是在谈论值类型,而是在谈论引用类型。对于这些,它将返回null。但是,OP 正在创建一个新实例并尝试返回它。对我来说,他似乎想返回一个实例而不是null
    • @DanielHilgarth 非常感谢,我收到了您的评论。将更新我的答案
    【解决方案2】:

    我能否建议您考虑这样的方法....

    class Program
    {
        static void Main(string[] args)
        {
    
            var client = new HttpClient();
    
            //basic authentication
    
            string baseURL = "myurl";
    
            var link = Link<Foo>.Create(baseURL);
    
            var response = client.SendAsync(link.CreateRequest()).Result;
    
            var myfoo = link.ProcessResponse(response);
    
        }
    
    }
    
    
    public class Link<T>
    {
        public Uri Target { get; set; }
    
        public static Link<T> Create(string url)
        {
            return new Link<T>() {Target = new Uri(url)};
        }
    
        public HttpRequestMessage CreateRequest()
        {
            return new HttpRequestMessage() {RequestUri = Target};
        }   
    
        public T ProcessResponse(HttpResponseMessage response)
        {
            if (response.IsSuccessStatusCode)
            {
                return response.Content.ReadAsAsync<T>().Result;
            }
            else
            {
                return new T(); //returns an instance, not null
            }
        }
    }
    
    public class Foo
    {
    
    }
    

    通过将创建链接的机制封装到静态工厂方法中并将响应处理封装到 ProcessResponse 方法中,您可以获得类似级别的可重用性,但您也可以获得重用相同 HttpClient 的好处。这使您可以真正利用 DefaultRequestHeaders,它会阻止 HttpClient 在处理连接时继续关闭连接。

    此外,通过避免将异步调用包装在同步方法中,您可以让调用代码决定是阻止结果还是异步处理它。您当前使用 .Result 的方式可能会在某些时候遇到死锁问题。

    这种创建 Link 类以封装与取消引用 URL 有关的特定行为的技术非常有用。添加可用于填写 URI 模板的参数很容易。您也可以使用它来处理请求正文。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-07
      • 1970-01-01
      • 1970-01-01
      • 2012-12-01
      • 1970-01-01
      相关资源
      最近更新 更多