如何不复制代码?通用和非通用实现 - 使用相同的主体

问题描述 投票:0回答:1

请告诉我我应该如何修改这段代码,以免复制/粘贴太多?有什么方法可以将泛型称为非泛型?我应该将

<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# .net generics refactoring
1个回答
1
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.