HttpClient与HttpClientHandler是否销毁?代码重构等价性及资源释放确认
代码重构与资源销毁疑问解答
问题描述
我想优化现有代码,目前多个API的HttpClient和HttpClientHandler结构相似,但对资源销毁有疑问。我知道using语句可以自动释放这类资源,想问问能不能把代码重构为抽离SetClientSettings方法的版本,重构后的两种写法是否等价,资源能不能始终被正确销毁?
原有代码
public static async Task<IEnumerable<T>> deletePostsAsync<T>(IEnumerable<string> urls) where T : BaseReturnValues { var httpClientHandler = new HttpClientHandler { Proxy = new WebProxy(proxy, true), UseProxy = IsProxySelected }; using (var client = new HttpClient(httpClientHandler)) { client.BaseAddress = new Uri(URI); client.DefaultRequestHeaders.Clear(); client.DefaultRequestHeaders.Add(Head.key, Head.apikey); var tasks = urls.Select(async url => await DeleteAsync<T>(client, url).ConfigureAwait(false)); var result = await Task.WhenAll(tasks).ConfigureAwait(false); return result!; } async Task<U> DeleteAsync<U>(HttpClient client, string url) where U : BaseReturnValues { var statusCode = -1; var json = "_"; var isSuccess = false; try { using (HttpResponseMessage response = await client.DeleteAsync(url).ConfigureAwait(false)) { statusCode = (Int32)response.StatusCode; json = await response.Content.ReadAsStringAsync(); isSuccess = response.IsSuccessStatusCode; } } catch (Exception ex) { // 异常处理逻辑 } // 省略其他逻辑,返回对应结果 return record; } }
重构后代码
public static async Task<IEnumerable<T>> deletePostsAsync<T>(IEnumerable<string> urls) where T : BaseReturnValues { using (var client = SetClientSettings()) { var tasks = urls.Select(async url => await DeleteAsync<T>(client, url).ConfigureAwait(false)); var result = await Task.WhenAll(tasks).ConfigureAwait(false); return result!; } async Task<U> DeleteAsync<U>(HttpClient client, string url) where U : BaseReturnValues { // 省略原有逻辑,返回对应结果 return record; } } public static HttpClient SetClientSettings() { var httpClientHandler = new HttpClientHandler { Proxy = new WebProxy(proxy, true), UseProxy = IsProxySelected }; var client = new HttpClient(httpClientHandler); client.BaseAddress = new Uri(URI); client.DefaultRequestHeaders.Clear(); client.DefaultRequestHeaders.Add(Head.key, Head.apikey); return client; }
核心疑问
以下两段代码是否完全等价?
代码片段1
var httpClientHandler = new HttpClientHandler { Proxy = new WebProxy(proxy, true), UseProxy = IsProxySelected }; using (var client = new HttpClient(httpClientHandler)) { client.BaseAddress = new Uri(URI); client.DefaultRequestHeaders.Clear(); client.DefaultRequestHeaders.Add(Head.key, Head.apikey); var tasks = urls.Select(async url => await DeleteAsync<T>(client, url).ConfigureAwait(false)); var result = await Task.WhenAll(tasks).ConfigureAwait(false); return result!; }
代码片段2
using (var client = SetClientSettings()) { var tasks = urls.Select(async url => await DeleteAsync<T>(client, url).ConfigureAwait(false)); var result = await Task.WhenAll(tasks).ConfigureAwait(false); return result!; }
回答
- 两段代码完全等价:
SetClientSettings方法只是把HttpClientHandler的创建、HttpClient的实例化和配置逻辑抽离出来,本质上和代码片段1做的事情一模一样。重构只是把重复的配置逻辑封装,没有改变对象的生命周期和资源管理方式。另外注意重构后的SetClientSettings方法返回值你写成了Httpclient,大小写错误,需要修正为HttpClient,否则编译不通过。 - 资源销毁完全正确:当
using块结束时,HttpClient会被自动调用Dispose方法。通过new HttpClient(httpClientHandler)创建客户端时,默认情况下HttpClient会接管传入的HttpClientHandler的生命周期,在自身Dispose时也会自动释放HttpClientHandler的资源。所以不管是原代码还是重构后的代码,HttpClient和HttpClientHandler都会被正确销毁,不会出现资源泄漏。 - 这个重构是合理的:把重复的客户端配置逻辑抽成公共方法,能有效减少代码冗余,多个API调用都可以复用这个方法,后续修改配置也只需要改一处,维护性更好。
内容的提问来源于stack exchange,提问作者Frenchy
相关产品推荐
相关产品推荐

