如何在实现IDependencyResolver和IDependencyScope的类中编写Dispose?

时间:2014-01-09 00:07:18

标签: dependency-injection castle-windsor code-analysis dispose suppressfinalize

我在我的Web API项目上运行了Code Analysis,我正在尝试使用Castle Windsor实现IoC和DI,它发现了四个问题。它发现的四件事都在WindsorDependencyResolver中,所有四件都是“正确实现IDisposable”,即:

0) CA1063正确实现IDisposable在'WindsorDependencyResolver'上提供Dispose(bool)的可覆盖实现或将类型标记为已密封。对Dispose(false)的调用应该只清理本机资源。对Dispose的调用(true)应该清理托管和本机资源。

指向这行代码:

public class WindsorDependencyResolver : System.Web.Http.Dependencies.IDependencyResolver

1) CA1063正确实现IDisposable修改'WindsorDependencyResolver.Dispose()'以便它调用Dispose(true),然后在当前对象实例上调用GC.SuppressFinalize(在Visual Basic中为'this'或'Me'),然后返回。

指向这行代码:

public void Dispose()

2)与O相同,但对于WindsorDependencyScope:IDependencyScope类。

3)与1相同,但是“”

我在线获取Castle Windsor文章的代码,主要来自this post。该文件的完整代码是:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http.Dependencies;
using Castle.Windsor;
using Castle.MicroKernel.Registration;
using System.Web.Http;
using Castle.MicroKernel.Lifestyle;
using Castle.MicroKernel.SubSystems.Configuration;
using HandheldServer.Models;

namespace HandheldServer
{
    public class WindsorDependencyResolver : System.Web.Http.Dependencies.IDependencyResolver
    {
        private readonly IWindsorContainer _container;

        public WindsorDependencyResolver(IWindsorContainer container)
        {
            _container = container;
        }

        public IDependencyScope BeginScope()
        {
            return new WindsorDependencyScope(_container);
        }

        public object GetService(Type serviceType)
        {
            return _container.Kernel.HasComponent(serviceType) ? _container.Resolve(serviceType) : null;
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            if (!_container.Kernel.HasComponent(serviceType))
            {
                return new object[0];
            }

            return _container.ResolveAll(serviceType).Cast<object>();
        }

        public void Dispose()
        {
            _container.Dispose();
        }
    }

    public class WindsorDependencyScope : IDependencyScope
    {
        private readonly IWindsorContainer _container;
        private readonly IDisposable _scope;

        public WindsorDependencyScope(IWindsorContainer container)
        {
            this._container = container;
            this._scope = container.BeginScope(); 
        }

        public object GetService(Type serviceType)
        {
            if (_container.Kernel.HasComponent(serviceType))
            {
                return _container.Resolve(serviceType);
            }
            else
            {
                return null;
            }
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return this._container.ResolveAll(serviceType).Cast<object>();
        }

        public void Dispose()
        {
            this._scope.Dispose();
        }
    }

    public class ApiControllersInstaller : IWindsorInstaller
    {
        public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
        {
            container.Register(Classes.FromThisAssembly() // should it be Types instead of Classes?
             .BasedOn<ApiController>()
             .LifestylePerWebRequest());
        }
    }

    // This idea from https://github.com/argeset/set-locale/blob/master/src/client/SetLocale.Client.Web/Configurations/IocConfig.cs
    public class ServiceInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(
                Component.For<IDeliveryItemRepository>().ImplementedBy<DeliveryItemRepository>().LifestylePerWebRequest(),
                Component.For<IDeliveryRepository>().ImplementedBy<DeliveryRepository>().LifestylePerWebRequest(),
                Component.For<IDepartmentRepository>().ImplementedBy<DepartmentRepository>().LifestylePerWebRequest(),
                Component.For<IExpenseRepository>().ImplementedBy<ExpenseRepository>().LifestylePerWebRequest(),
                Component.For<IInventoryItemRepository>().ImplementedBy<InventoryItemRepository>().LifestylePerWebRequest(),
                Component.For<IInventoryRepository>().ImplementedBy<InventoryRepository>().LifestylePerWebRequest(),
                Component.For<IItemGroupRepository>().ImplementedBy<ItemGroupRepository>().LifestylePerWebRequest());
        }
    }
}

安抚代码分析工具的最佳方法是什么?

1 个答案:

答案 0 :(得分:3)

在回答您的问题之前,请注意您应该非常小心地在您没有创建的对象上调用Dispose(),因此可能不负责。我的意思是这条线

_container.Dispose();

container被传递,所以严格来说,处理不属于你。

安抚代码分析工具的最简单方法是按照建议实施IDisposable

public class WindsorDependencyResolver
{
    public WindsorDependencyResolver()
    {
    }

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

    private bool disposed;

    protected virtual void Dispose(bool disposing)
    {
        if (this.disposed) return;

        if (disposing)
        {
            // call dispose on managed resources
            // set to null
        }

        this.disposed = true;
    }
}

请参阅here以获得对原因的详尽解释,然后提出许多合理的论据,为何不这样做!我建议在一天结束时你应该坚持你所选择的标准,如果那包括代码分析工具,那就这样吧。