IDisposable 的实际实现

Actual implementation of 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);
}


Class: 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);
    }
}


考虑以下 class、接口 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:当我已经解决了依赖关系时,为什么会抛出空异常。为避免这种情况,我必须添加以下行:

_apiClient.DefaultRequestHeaders = new HttpClientAdaptor().DefaultRequestHeaders;

有没有更好的方法来做到这一点,而不是在我需要的任何地方使用上面提到的代码DefaultRequestHeader

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

问题 3:考虑 class HttpClientAdaptor 和评论 // Question 3。这是处理托管代码的正确方法吗?如果是那么我应该如何处理 属性 BaseAddress?如果没有,请提出正确的方法。当然,由于显而易见的原因,当前代码会给出编译时错误。

问题一: 如评论中所述,没有 DI 通过调用 get 属性来初始化您的字段,因此您需要做的是将初始化移动到构造函数中。

问题 2:有点不清楚你想要实现什么,正如你在评论中指出的那样,你将它用于单元测试。一个人不在模拟中进行实际调用。那么也许您还需要其他东西?例如。记住调用发生了,可能还有调用时使用的参数。

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

  1. 您有一个 IDisposable 的会员,您需要在
  2. 上致电 Dispose
  3. 您直接有一些非托管资源

这些似乎都不是你的情况,所以你真的不需要在 dispose 中做任何事情,因为看起来只有你拥有它,因为你正在重新 -实现系统接口。

这仍然意味着那些将使用您的 HttpClientAdaptor class 的人需要进行处理,因为他们不知道它实际上什么都不做。当然,如果您自己使用它,您可以跳过调用 dispose 而不会产生任何后果。

P.S。如果您使用 class 进行单元测试,则可以使用专用于此目的的模拟库之一,并将动态完成这项工作。 MoqNSubstitute 是不错的候选人。