.net 如何不复制代码?泛型和非泛型实现-使用相同主体

6qftjkof  于 2023-03-13  发布在  .NET
关注(0)|答案(1)|浏览(161)

请告诉我,我应该如何修改这段代码,这样就不会有太多的复制/粘贴了?有没有办法把泛型称为非泛型?我应该把<object>传递给泛型并对此感到满意吗?最好的解决方案是什么?
我举个例子

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)
tcomlyy6

tcomlyy61#

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”值从未在任何地方使用过。

相关问题