Castle Windsor可以在使用Typed Factory创建后释放组件

时间:2012-11-14 02:24:17

标签: c# castle-windsor

我正在使用Windsor 3.1.0并使用Typed Factory使用LifestyleTransient实例化组件。正如在参考页面中所说,我必须释放我从工厂获得的每个对象。但是我的情况看起来像这样

class MyTypedFactory
{
    MyTransientCommand CreateCommand();
    void Release(MyTransientCommand command);
}

class MyTransientCommand
{
    public void Execute() { }
}

class ClassA
{
    public ClassB CommandPopulator { get; set; }

    public void Foo()
    {
        List<MyTransientCommand> commands = new List<MyTransientCommand>();

        CommandsPopulator.Commands = commands;

        for (int i=0; i<100; ++i)
        {
            CommandsPopulator.Bar();
        }

        foreach (MyTransientCommand command in commands)
        {
            command.Execute();
        }
    }
}

class ClassB
{
    public MyTypedFactory Factory { get; set; }

    List<MyTransientCommand> Commands { get; set; }

    public void Bar()
    {
        Commands.Add(Factory.CreateCommand());
    }
}

这可能看起来过于复杂,但它说明了我的代码中的对象流。这里外部类(ClassB)使用由类型化工厂创建的命令填充commands队列。

当不再需要这些对象(在Execute循环之后)与工厂成为完整问题时释放它们。我可以在循环中释放但是对于释放方法本身的例外是不安全的。

class ClassA
{
    public MyTypedFactory Factory { get; set; }

    ...

    public void Foo()
    {
        ...
        foreach (MyTransientCommand command in commands)
        {
            command.Execute();
        }

        foreach (MyTransientCommand command in commands)
        {
            Factory.Release(command);
        }
    }
}

如果其中一个Release调用抛出,其余的对象将不会被释放并且会导致内存泄漏(我知道这不会发生,但我会尝试防范此类内容)。

MyTransientCommand创建ClassB.Bar之后立即发布是否可以?在ClassA.Foo方法返回之前,它不会被GC释放,因为它保存了对命令对象集合的引用。

如果MyTransientCommand进行WCF客户端调用并且WCF客户端设置为Windsor,是否可以在ClassB.Bar中释放MyTransientCommand.Execute?或者更常见的是,如果MyTransientCommand.Execute使用Windsor提供的其他组件?

P.S。问题中的代码看起来是人为的,不自然的。这是因为算法必须有副作用:在某些情况下,在事务中更改数据库中的数据状态必须引发WCF调用。这些调用必须在交易完成后不在交易期间进行。

2 个答案:

答案 0 :(得分:0)

通常我会依赖创建/注入对象的类来负责释放它,但它不会导致任何问题以你描述的方式释放它 - 你可以将释放代码放在{{ 1}}。

finally

为了扩展一点,Castle将注入所有必要的依赖项(只要你的工厂设置正确)。从容器中释放对象只是释放该实例。如果您在foreach (var command in commands) { try { command.Execute(); } finally { Factory.Release(command); } } 方法中修改注入的LifestyleSingleton对象,则可能会遇到并发问题,但这与从容器中释放它无关。

答案 1 :(得分:0)

不,在使用它之前发布组件是不行的。 Windsor跟踪嵌套组件的生命周期,因此释放根组件通常可以释放它的子组件。我想避免使用可能无效的组件。

所以我最终采用以下方式发布commands

class ClassA
{
    public MyTypedFactory Factory { get; set; }
    public ClassB CommandPopulator { get; set; }

    public void Foo()
    {
        List<MyTransientCommand> commands = new List<MyTransientCommand>();

        try
        {
            CommandsPopulator.Commands = commands;

            for (int i=0; i<100; ++i)
            {
                CommandsPopulator.Bar();
            }

            foreach (MyTransientCommand command in commands)
            {
                command.Execute();
            }
        }
        finally
        {
            foreach (MyTransientCommand command in commands)
            {
                try
                {
                    Factory.Release(command);
                }
                catch (Exception exception)
                {
                    Log(exception);
                }
            }
        }
    }
}

这样我确定如果在使用CommandsPopulator或执行命令时发生异常,所有命令仍然会被释放。此外,每个命令都在try / catch块中释放,以防止从一个Release抛出循环引发异常。

希望Windsor遵循无抛出语义来释放具有Typed Factory的对象,或者异常发生的可能性非常低。