请告诉我我应该如何修改这段代码,以免复制/粘贴太多?有什么方法可以将泛型称为非泛型?我应该将
<object>
传递给 generic 并对此感到满意吗?什么是最佳解决方案?
我有例如
public interface IHttpService
{
Task<T> Post<T>(string uri, HttpContent content, int timeOut = 100, CancellationToken token = default);
Task Post(string uri, HttpContent content, int timeOut = 100, CancellationToken token = default);
}
所以他们有几乎相同但不同的实现
public async Task Post(string uri, HttpContent content, int timeOut = 100, CancellationToken token = default)
{
var request = new HttpRequestMessage(HttpMethod.Post, uri);
request.Content = content;
await sendRequest(request, timeOut, token);
}
public async Task<T> Post<T>(string uri, HttpContent content, int timeOut = 100, CancellationToken token = default)
{
var request = new HttpRequestMessage(HttpMethod.Post, uri);
request.Content = content;
return await sendRequest<T>(request, timeOut, token);
}
private async Task sendRequest(HttpRequestMessage request, int timeOut = 100, CancellationToken token = default)
{
try
{
using var requestCTS = new CancellationTokenSource(TimeSpan.FromSeconds(timeOut));
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(requestCTS.Token, token);
using var response = await _httpClient.SendAsync(request, linkedCts.Token);
if (!response.IsSuccessStatusCode)
{
var error = await response.Content.ReadAsStringAsync(token);
throw new Exception(error);
}
}
private async Task<T> sendRequest<T>(HttpRequestMessage request, int timeOut = 100, CancellationToken token = default)
{
try
{
using var requestCTS = new CancellationTokenSource(TimeSpan.FromSeconds(timeOut));
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(requestCTS.Token, token);
using var response = await _httpClient.SendAsync(request, linkedCts.Token);
if (!response.IsSuccessStatusCode)
{
var error = await response.Content.ReadAsStringAsync(token);
throw new Exception(error);
}
return (await response.Content.ReadFromJsonAsync<T>())!;
}
更新
private async Task<HttpContent> sendRequest(HttpRequestMessage request, int timeOut = 100, CancellationToken token = default)
{
try
{
using var requestCTS = new CancellationTokenSource(TimeSpan.FromSeconds(timeOut));
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(requestCTS.Token, token);
using var response = await _httpClient.SendAsync(request, linkedCts.Token);
if (!response.IsSuccessStatusCode)
{
await response.Content.ReadAsStringAsync(token);
throw new Exception(error);
}
return response.Content;
}
catch (AccessTokenNotAvailableException)
{
_navigationManager.NavigateToLogout(StaticStringHelper.LogoutPatch);
return default(HttpContent)!;
}
}
当我像这样使用它时
public async Task<T> Get<T>(string uri, int timeOut = 100, CancellationToken token = default)
{
var request = new HttpRequestMessage(HttpMethod.Get, uri);
return await (await sendRequest(request, timeOut, token)).ReadFromJsonAsync<T>(cancellationToken: token);
}
我知道
microsoft.AspNetCore. Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Cannot access a disposed object.
Object name: 'System.Net.Http.BrowserHttpContent'.
System. ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.Http.BrowserHttpContent'.
at System.Net.Http.HttpContent.CheckDisposed()
at System.Net.Http.HttpContent.ReadAsStreamAsync(CancellationToken cancellationToken)
C# 中没有通用的“void”。在某些情况下,您可以只使用带有 int 或 bool 之类的泛型作为无意义的值。在其他情况下,你只需要接受它并保留两个实现。
在这种特殊情况下,唯一的区别似乎是
response.Content.ReadFromJsonAsync<T>()
,因此您应该能够重构它以使所有其他代码通用。由于内容已处理,您需要使用委托来注入不同的代码:
public Task Post(string uri, HttpContent content, int timeOut = 100, CancellationToken token = default)
=> Post<int>(uri, content, c => Task.FromResult(0), timeOut , token);
public async Task<T> Post<T>(string uri, HttpContent content, int timeOut = 100, CancellationToken token = default)
=> Post(uri, content, ReadFromJson, timeOut , token)!;
private Task<T> ReadFromJson(HttpContent content) => content.ReadFromJsonAsync<T>();
private async Task<T> Post<T>(string uri, HttpContent content, Func<HttpContent, Task<T>> handleContent, int timeOut = 100, CancellationToken token = default)
{
var request = new HttpRequestMessage(HttpMethod.Post, uri);
request.Content = content;
try
{
using var requestCTS = new CancellationTokenSource(TimeSpan.FromSeconds(timeOut));
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(requestCTS.Token, token);
using var response = await _httpClient.SendAsync(request, linkedCts.Token);
if (!response.IsSuccessStatusCode)
{
var error = await response.Content.ReadAsStringAsync(token);
throw new Exception(error);
}
return await handleContent(response.Content);
}
c => Task.FromResult(0)
只是使通用类型适合的东西,“0”值从未在任何地方使用过。