IDisposable

时间:2018-07-23 12:33:19

标签: c# idisposable

注意:标题是一个问题,但实际上我有3个问题要问。
我正在使用Autofac DI容器来解决依赖关系。
如果对此代码还有其他改进,请提出建议。
我已经浏览了以下链接:
Implementing IDisposable correctly
Implementing a Dispose method
IDisposable Part 1

请考虑以下代码:
界面:IHttpClient

public interface IHttpClient : IDisposable
{
    HttpRequestHeaders DefaultRequestHeaders { get; set; }    // Question 1

    Uri BaseAddress { get; set; }

    Task<HttpResponseMessage> PostAsync(string uri, HttpContent httpContent);
}


类:HttpClientAdaptor

internal HttpClientAdaptor : IHttpClient
{
    private HttpRequestHeaders _defaultRequestHeaders;
    private bool _disposed = false;

    public HttpRequestHeaders DefaultRequestHeaders
    {
        get
        {
            if (_defaultRequestHeaders == null)
                _defaultRequestHeaders = new HttpClient().DefaultRequestHeaders;

                return _defaultRequestHeaders;
        }    
        set
        {
            if (value != null)
                _defaultRequestHeaders = value;
        }
    }

    public Uri BaseAddress { get; set; }

    private async Task<HttpResponseMessage> PostAsync(Uri uri, HttpContent httpContent, CancellationToken cancellationToken)
    {
        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri)
        {
            Content = httpContent
        };

        return await new HttpMessageInvoker(new HttpClientHandler()).SendAsync(request, cancellationToken);     // Question 2
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                _defaultRequestHeaders = null;
                BaseAddress = new Uri();      // Question 3
            }

            _disposed = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}


考虑以下类,接口IHttpClient// Question 1

class DS
{
    private IHttpClient _apiClient;

    public class DS(/*other dependencies*/, IHttpClient apiClient)
    {
        _apiClient = apiClient;
    }

    // At somepoint I need to perform the following operation
    private void SomeMethod(string hostname, /*other params*/)
    {
        _apiClient.BaseAddress = new Uri(hostName);
        _apiClient.DefaultRequestHeaders.Accept.Clear();   // this line throws exception as "DefaultRequestHeaders" is null
        _apiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    }
}

问题1 :当我已经解决依赖项时,为什么会引发null异常。为了避免这种情况,我必须添加以下行:

_apiClient.DefaultRequestHeaders = new HttpClientAdaptor().DefaultRequestHeaders;

是否有更好的方法,而不是在需要DefaultRequestHeader的任何地方都使用上面提到的代码?

问题2 :考虑class HttpClientAdaptor并评论// Question 2。我需要拨打SendAsync()。这是正确的方法还是我应该继承class HttpMessageInvoker。还是有第三种方法?

问题3 :考虑class HttpClientAdaptor并评论// Question 3。这是处置托管代码的正确方法吗?如果是,那我应该如何处置财产BaseAddress?如果没有,请提出正确的建议。当然,由于明显的原因,当前代码会给出编译时错误。

1 个答案:

答案 0 :(得分:1)

问题1: 如注释中所述,没有DI会通过调用get属性来初始化字段,因此您需要做的是在构造函数中移动初始化。

问题2:正如要在单元测试中使用注释中指出的那样,您尚不清楚要实现什么目标。一个人不要在模拟中进行实际的调用。因此,也许您还需要其他东西?例如。要记住调用发生了,并且调用时可能使用了参数。

问题3: 不,这似乎不是处理您实现它的方式的正确方法。在以下两种情况下,需要实施IDisposable

  1. 您有一个IDisposable成员,您需要在此呼叫Dispose
  2. 您直接拥有一些不受管理的资源

您似乎并没有遇到任何这样的情况,因此您根本不需要在内部处理任何事情,因为由于您正在重新实现系统,因此看来您根本就没有它。界面。

这仍然意味着,尽管那些将使用您的HttpClientAdaptor类的人将需要进行处分,因为他们不知道它实际上没有任何作用。当然,如果您自己使用它,也可以跳过调用处置,而不会产生任何后果。

P.S。如果将您的类用于单元测试,则可以使用为此目的而设计的模拟库之一,它将动态地完成这项工作。 MoqNSubstitute是很好的候选人。