代码之家  ›  专栏  ›  技术社区  ›  stakx - no longer contributing Saravana Kumar

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

  •  10
  • stakx - no longer contributing Saravana Kumar  · 技术社区  · 15 年前

    我目前正在学习如何使用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
    }
    

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

    delegate IApple AppleFactory;
    

    自动传真配置:

    Apple Horse ,因为它们的实现非常简单:

    var builder = new Autofac.ContainerBuilder();
    
    builder.RegisterType<Apple>().As<IApple>();
    builder.RegisterType<Horse>().As<IHorse>();
    builder.RegisterType<HorseKeeper>().As<IHorseKeeper>();
    builder.RegisterGeneratedFactory<AppleFactory>();
    

    我的问题是:

    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!
        }
    }
    

    这是我想要的代码类型,因为它完全不受Autofac的影响。它也可以与另一个IoC容器一起工作,只要 AppleFactory 一切正常。

    但是,由于Autofac处理 对我来说,它将记录所有 嬉笑 它为我生成的对象,并因此希望 Dispose apple 将被处理两次。

    我想是注册吧 作为 .ExternallyOwned() 没有可行的解决方案,因为在某些情况下,让Autofac处理 嬉笑 一个人的一生。

    Deterministic disposal with Autofac 需要使用创建嵌套容器 container.BeginLifetimeScope() HorseKeeper.FeedHorse HorseKeeper 变得依赖于Autofac,我希望我的代码与IoC无关。

    问题:

    如何实现 牧马人 以IoC(Autofac)-不可知的方式,同时确保正确处理动态生成的对象?

    3 回复  |  直到 15 年前
        1
  •  15
  •   Tim Cooper    13 年前

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

    Autofac 2在此提供了一个新的帮助功能,称为“自有实例”。我注意到您的注册码是Autofac 1.4,因此如果您无法升级,请告诉我(还有其他不太透明的方法)

    照常注册苹果(非外部所有):

    builder.RegisterType<Apple>().As<IApple>();
    

    将AppleFactory声明为:

    public delegate Owned<IApple> AppleFactory();
    

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

    然后,在《马夫》中,像这样喂马:

    public void FeedHorse()
    {
        using (var apple = appleFactory())
        {
            horse.Eat(apple.Value);
        }
    }
    

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

    在使用块结束时,将清除苹果及其所有依赖项。

        2
  •  3
  •   Peter Lillevold Rene    15 年前

    唯一的方法是修改苹果的注册 ExternallyOwned 修饰语。这指示Autofac不要跟踪要处理的对象,而是让外部人员(您的代码)处理处理。但正如您所说,您现在必须确保手动处理所有Apple实例,因为您不会从Autofac获得自动帮助。

    builder.RegisterType<Apple>().As<IApple>().ExternallyOwned();
    

    不过,通过此注册,您的提要代码将按预期工作。

    :关于接口是否应继承的讨论 IDisposable ,这是向“消费型”开发人员指示应在某个时间点处置实例。在IApple的情况下,由于该接口也是IDisposable的,开发人员应该确保处置实例(和 必须 也可以注册为外部所有者)。另一方面,如果Apple类是这样的:

    class Apple: IApple, IDisposable
    { }
    

    IApple的消费者现在完全不知道实例是可识别的。在这种情况下,我们将让容器处理处置。

    因此,我的结论是,作为苹果和IApple的开发者,我可以选择是要求消费者处理垃圾,还是将垃圾留给一个容器。

        3
  •  2
  •   Wim Coenen    15 年前

    public IApple
    {
       void Consume();
    }
    
    public IDisposableApple : IApple, IDisposable
    {
    }
    

    然后注册该类两次:

    builder.RegisterType<Apple>().As<IApple>();
    builder.RegisterType<Apple>().As<IDisosableApple>().ExternallyOwned(); 
    

    然后,您可以将DisposableAppleFactory注入到需要创建和dispose Apple的类中。

    对于只需要一个与容器具有相同生存期的apple的类,可以注入IApple。

    然而,事实上,你需要两者都可能表明你是混合 newables and injectables . 苹果可能只是一个“可更新”的对象,即不需要由IoC容器管理的对象。