C# 您如何协调IDisposable和IoC?

C# 您如何协调IDisposable和IoC?,c#,inversion-of-control,unity-container,idisposable,C#,Inversion Of Control,Unity Container,Idisposable,我终于在C#中把我的头缠在IoC和DI上了,我正在与一些边缘作斗争。我使用的是Unity容器,但我认为这个问题适用范围更广 使用IoC容器分发实现IDisposable的实例让我抓狂!你怎么知道你是否应该处理()?该实例可能只是为您创建的(因此您应该Dispose()它),也可能是在其他地方管理其生命周期的实例(因此您最好不要这样做)。代码中没有任何内容告诉您,事实上,这可能会根据配置而改变!!!这对我来说似乎是致命的 国际奥委会的专家们能描述出处理这种模糊性的好方法吗?我认为一般来说,最好的方

我终于在C#中把我的头缠在IoC和DI上了,我正在与一些边缘作斗争。我使用的是Unity容器,但我认为这个问题适用范围更广

使用IoC容器分发实现IDisposable的实例让我抓狂!你怎么知道你是否应该处理()?该实例可能只是为您创建的(因此您应该Dispose()它),也可能是在其他地方管理其生命周期的实例(因此您最好不要这样做)。代码中没有任何内容告诉您,事实上,这可能会根据配置而改变!!!这对我来说似乎是致命的


国际奥委会的专家们能描述出处理这种模糊性的好方法吗?

我认为一般来说,最好的方法就是不要处理已经注入的东西;您必须假设喷油器正在进行分配和解除分配。

这取决于DI框架。有些框架允许您为每个注入的依赖项指定是否需要共享实例(始终使用相同的引用)。在这种情况下,您很可能不想处置

如果您可以指定希望注入唯一实例,那么您将希望进行处置(因为它是专门为您构建的)。不过,我对Unity不太熟悉——您必须查看文档,了解如何在那里实现这一点。这是MEF和我尝试过的其他一些属性的一部分。

通过允许创建嵌套容器来处理此问题。当容器完成时,它会自动处理其中的所有IDisposable对象。更多

。。解析服务时,Autofac会跟踪已解析的一次性(IDisposable)组件。在工作单元结束时,您将处理相关的生存期范围,Autofac将自动清理/处理已解析的服务


您肯定不想对注入到类中的对象调用Dispose()。你不能假设你是唯一的消费者。最好将非托管对象包装到某个托管接口中:

public class ManagedFileReader : IManagedFileReader
{
    public string Read(string path)
    {
        using (StreamReader reader = File.OpenRead(path))
        {
            return reader.ReadToEnd();
        }
    }
}
这只是一个例子,如果我试图将文本文件读入字符串,我将使用File.ReadAllText(path)

另一种方法是注入工厂并自己管理对象:

public void DoSomething()
{
    using (var resourceThatShouldBeDisposed = injectedFactory.CreateResource())
    {
        // do something
    }
}

在Unity框架中,有两种方法注册注入的类:作为单例(解析时总是得到相同的类实例),或者在每次解析时都得到一个新的类实例

在后一种情况下,您有责任在不需要时处理已解决的实例(这是一种非常合理的方法)。另一方面,当您处理容器(处理对象解析的类)时,所有单例对象也会自动处理


因此,使用Unity框架注射一次性物品显然没有问题。我不知道其他框架,但我认为,只要依赖注入框架足够坚固,它肯定会以某种方式处理这个问题。

在容器前面放置一个外观也可以解决这个问题。此外,您还可以扩展它以跟踪更丰富的生命周期,如服务关闭和启动或ServiceHost状态转换

我的容器往往位于实现IServiceLocator接口的IExtension中。它是unity的门面,允许在WCf服务中轻松访问。此外,我还可以从ServiceHostBase访问服务事件

最后的代码将尝试查看是否有任何单例注册或创建的任何类型实现了facade跟踪的任何接口

仍然不允许及时处理,因为您与这些事件有关,但这有点帮助


如果您希望及时处理(又名,现在是服务关闭时的v.s.)。您需要知道,您获得的项目是一次性的,它是处理它的业务逻辑的一部分,因此IDisposable应该是对象接口的一部分。可能还应该验证与调用dispose方法相关的测试。

这也经常困扰着我。尽管我对此并不满意,但我总是得出这样的结论:永远不要以一种暂时的方式返回可识别的对象是最好的

最近,我为自己重新表述了这个问题:这真的是一个IoC问题,还是一个.net框架问题?不管怎么说,这很尴尬。它没有任何有意义的功能目的,只有技术目的。因此,我们必须处理的更多的是一个框架问题,而不是国际奥委会的问题

我喜欢DI的地方在于,我可以要求签订一份合同,为我提供功能,而不必担心技术细节。我不是主人。不知道它在哪一层。不知道履行合同需要哪些技术,不担心寿命。我的代码看起来很好,很干净,并且是高度可测试的。我可以在它们所属的层中实现职责

所以,如果这条规则有一个例外,需要我安排一生,那我们就破例吧。不管我喜不喜欢。如果实现接口的对象需要我处理它,我想知道它,因为我会被触发使用尽可能短的对象。一个技巧是使用一个子容器来解析它,这个子容器在一段时间后被释放,这可能仍然会导致我让对象保持活动的时间比我应该保持的时间长。对象的允许生存期在注册对象时确定。而不是通过创建子容器并将其保留一段时间的功能

所以,只要我们开发人员需要担心处理问题(这会改变吗?),我就会尝试注入尽可能少的瞬态一次性对象。 1.我试图使对象不是ID
using System;
using Microsoft.Practices.Unity;

namespace Test
{
    // Unity configuration
    public class ConfigurationExtension : UnityContainerExtension
    {
        protected override void Initialize()
        {
            // Container.RegisterType<IDataService, DataService>(); Use factory instead
            Container.RegisterType<IInjectionFactory<IDataService>, InjectionFactory<IDataService, DataService>>();
        }
    }

    #region General utility layer

    public interface IInjectionFactory<out T>
        where T : class
    {
        T Create();
    }

    public class InjectionFactory<T2, T1> : IInjectionFactory<T2>
        where T1 : T2
        where T2 : class

    {
        private readonly IUnityContainer _iocContainer;

        public InjectionFactory(IUnityContainer iocContainer)
        {
            _iocContainer = iocContainer;
        }

        public T2 Create()
        {
            return _iocContainer.Resolve<T1>();
        }
    }

    #endregion

    #region data layer

    public class DataService : IDataService, IDisposable
    {
        public object LoadData()
        {
            return "Test data";
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                /* Dispose stuff */
            }
        }

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

    #endregion

    #region domain layer

    public interface IDataService
    {
        object LoadData();
    }

    public class DomainService
    {
        private readonly IInjectionFactory<IDataService> _dataServiceFactory;

        public DomainService(IInjectionFactory<IDataService> dataServiceFactory)
        {
            _dataServiceFactory = dataServiceFactory;
        }

        public object GetData()
        {
            var dataService = _dataServiceFactory.Create();
            try
            {
                return dataService.LoadData();
            }
            finally
            {
                var disposableDataService = dataService as IDisposable;
                if (disposableDataService != null)
                {
                    disposableDataService.Dispose();
                }
            }
        }
    }

    #endregion
}