Autofac:如何在不绕过IoC容器的情况下限制IDisposable对象的生命周期

sta*_*ica 10 c# dispose idisposable inversion-of-control autofac

我目前正在学习如何使用Autofac,而且我坚持要IDisposable确定性地处理对象.在我陈述我的问题之前,让我首先介绍一下情况.

起始位置:

假设我的对象模型是通过以下接口定义的:

interface IApple : IDisposable
{
    void Consume();
}

interface IHorse
{
    void Eat(IApple apple);   // is supposed to call apple.Consume()
}

interface IHorseKeeper
{
    void FeedHorse();   // is supposed to call horse.Eat(apple)
                        //   where 'horse' is injected into IHorseKeeper
                        //   and 'apple' is generated by IHorseKeeper on-the-fly
}
Run Code Online (Sandbox Code Playgroud)

此外,我定义了一个将用作IApple工厂的委托:

delegate IApple AppleFactory;
Run Code Online (Sandbox Code Playgroud)

Autofac配置:

现在,如下我将寄存器的上述类型-请注意,我省略这两个类的代码AppleHorse,因为他们是容易实现:

var builder = new Autofac.ContainerBuilder();

builder.RegisterType<Apple>().As<IApple>();
builder.RegisterType<Horse>().As<IHorse>();
builder.RegisterType<HorseKeeper>().As<IHorseKeeper>();
builder.RegisterGeneratedFactory<AppleFactory>();
Run Code Online (Sandbox Code Playgroud)

我的问题:

我不太清楚如何实现方法IHorseKeeper.Feed.这是我现在拥有的:

class HorseKeeper : IHorseKeeper
{
    private readonly IHorse horse;
    private readonly AppleFactory appleFactory;

    public HorseKeeper(IHorse horse, AppleFactory appleFactory)
    //                 ^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^^^^
    //                         constructor injection
    {
        this.horse = horse;
        this.appleFactory = appleFactory;
    }

    public void FeedHorse()
    {
        using (var apple = appleFactory())
        {
            horse.Eat(apple);
        }  // <- Dispose() apple now (ASAP), as it's no longer needed!
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我想要的代码,因为它完全与Autofac无关.只要AppleFactory按预期工作,它也可以与另一个IoC容器一起使用.

但是,因为Autofac AppleFactory会为我处理它,它将跟踪IApple它为我生成的所有对象,因此Dispose在容器的生命周期结束时会想要它们.即,生产的产品apple将被处理两次.

我想注册IApple.ExternallyOwned()是没有可行的解决办法,因为可能有情况下,它更容易让Autofac处理IApples'的寿命.

使用Autofac进行确定性处理需要使用嵌套容器的创建container.BeginLifetimeScope(),但是我不想在内部使用它,HorseKeeper.FeedHorse因为它HorseKeeper依赖于Autofac,我想保持我的代码与IoC无关.

题:

如何HorseKeeper.FeedHorse以IoC(Autofac)为中心的方式实现,同时确保正确处理动态生成的对象?

Nic*_*rdt 15

这里的其他答案很有见地,但有问题.在这两种情况下,如果Apple有其他需要处理的依赖项,则不会进行正确的清理.

Autofac 2提供了一个新功能来帮助这里,称为"拥有实例".我注意到您的注册码是Autofac 1.4,所以如果您无法升级请告诉我(还有其他不太透明的方法可以做到这一点.)

像往常一样注册Apple(非外部拥有):

builder.RegisterType<Apple>().As<IApple>();
Run Code Online (Sandbox Code Playgroud)

将AppleFactory声明为:

public delegate Owned<IApple> AppleFactory();
Run Code Online (Sandbox Code Playgroud)

在Autofac 2中,您不再需要调用RegisterGeneratedFactory() - 这是自动的.

然后,在HorseKeeper中,像这样喂马:

public void FeedHorse()
{
    using (var apple = appleFactory())
    {
        horse.Eat(apple.Value);
    }
}
Run Code Online (Sandbox Code Playgroud)

(注意.Value属性以获取基础IApple.

在使用块结束时,将清除apple及其所有依赖项.

直接使用IApple的任何其他组件(作为依赖项)将获得通常的行为.