DI:处理IDisposable对象的生命

cta*_*cke 8 c# dependency-injection compact-framework ioc-container opennetcf.ioc

所以我正在研究我的DI/IoC容器OpenNETCF.IoC,我有一个(合理的)功能请求,为容器集合中的IDisposable项添加某种形式的生命周期管理.

我当前的想法是,因为我不能查询一个对象以查看它是否已被处理,并且我无法获得一个事件,因为它被处理掉了,我必须为开发人员想要的对象创建某种形式的包装器要管理的框架.

现在可以使用AddNew添加对象(为简单起见,我们假设只有一个重载,并且没有Add):

public TTypeToBuild AddNew<TTypeToBuild>() { ... }
Run Code Online (Sandbox Code Playgroud)

我正在考虑的是添加一种新方法(很好的一组,但你得到的图片):

public DisposableWrappedObject<IDisposable> AddNewDisposable<TTypeToBuild>()
    where TTypeToBuild : class, IDisposable
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

DisposableWrappedObject的位置如下所示:

public class DisposableWrappedObject<T>
    where T : class, IDisposable
{
    public bool Disposed { get; private set; }
    public T Instance { get; private set; }

    internal event EventHandler<GenericEventArgs<IDisposable>> Disposing;

    internal DisposableWrappedObject(T disposableObject)
    {
        if (disposableObject == null) throw new ArgumentNullException();

        Instance = disposableObject;
    }

    ~DisposableWrappedObject()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
    }

    protected virtual void Dispose(bool disposing)
    {
        lock(this)
        {
            if(Disposed) return;

            EventHandler<GenericEventArgs<IDisposable>> handler = Disposing;
            if(handler != null)
            {
                Disposing(this, new GenericEventArgs<IDisposable>(Instance));
            }

            Instance.Dispose();

            Disposed = true;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,当一个项目通过AddNewDIsposable添加到容器时,还会添加一个事件处理程序,以便在它获得Disposed时(通过包装器),框架将其从底层集合中删除.

我实际上已经实现了这个并且通过了单元测试,但我正在寻找关于这可能会被打破的意见,或者它如何对消费者开发者更加"友好".

编辑1

由于有关于如何使用Disposing事件的问题,这里有一些代码(修剪到重要的内容):

private object AddNew(Type typeToBuild, string id, bool wrapDisposables)
{
    ....

    object instance = ObjectFactory.CreateObject(typeToBuild, m_root);

    if ((wrapDisposables) && (instance is IDisposable))
    {
        DisposableWrappedObject<IDisposable> dispInstance = new
               DisposableWrappedObject<IDisposable>(instance as IDisposable);
        dispInstance.Disposing += new 
               EventHandler<GenericEventArgs<IDisposable>>(DisposableItemHandler);
        Add(dispInstance as TItem, id, expectNullId);
        instance = dispInstance;
    }

    ....

    return instance;
}

private void DisposableItemHandler(object sender, GenericEventArgs<IDisposable> e)
{
    var key = m_items.FirstOrDefault(i => i.Value == sender).Key;
    if(key == null) return;
    m_items.Remove(key);
}
Run Code Online (Sandbox Code Playgroud)

Tru*_*ill 3

也许我遗漏了一些东西,但为什么要向 API 添加新方法呢?当一个对象被添加到容器中时,您可以进行 as-cast 来检查它是否是 IDisposable,如果是,则进行适当的处​​理。

我还想知道你是否需要析构函数。假设容器是 IDisposable(如 Unity 的),您可以只实现基本 Dispose 模式并节省大量 GC 开销。

一些可能适用的问题:

  • @ctacke:消费者在使用 IoC 时必须遵循一些规则:当您将“创建”对象的责任移交给 DI 容器时,您必须移交“所有”生命周期管理,包括实例的“销毁”。因此,如果消费者过早地处理注入的依赖项,那么在消费者方面将是一个错误,因为该实例可能在多个消费者之间共享。我认为您不需要使 API 过于复杂来防止完全错误的使用。 (5认同)