C# Castle Windsor使用类型化工厂创建组件后是否可以发布组件

C# Castle Windsor使用类型化工厂创建组件后是否可以发布组件,c#,castle-windsor,C#,Castle Windsor,我正在使用Windsor 3.1.0,并使用LifestyleTransient实例化一个组件。正如在参考页面中所说,我必须释放我从工厂得到的每一件物品。然而,我在这样的场景中 class MyTypedFactory { MyTransientCommand CreateCommand(); void Release(MyTransientCommand command); } class MyTransientCommand { public void Execut

我正在使用Windsor 3.1.0,并使用
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.Bar
中创建了
MyTransientCommand
后立即释放该命令可以吗?在
ClassA.Foo
方法返回之前,GC不会释放它,因为它持有对commands对象集合的引用

如果
MyTransientCommand.Execute
进行WCF客户端调用并且WCF客户端已与Windsor一起设置,则在
ClassB.Bar
中释放
MyTransientCommand
是否可以?或者更一般地说,如果MyTransientCommand.Execute使用Windsor提供的其他组件


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

通常,我会依赖于创建/注入对象的类来负责释放它,但以您描述的方式释放它不应该导致任何问题-您可以将释放代码放在一个

foreach (var command in commands)
{
    try
    {
        command.Execute();
    }
    finally
    {
        Factory.Release(command);
    }
}

为了扩展一点,Castle将注入所有必要的依赖项(只要您的工厂设置正确)。从容器中释放对象就是释放该实例。如果在
Execute()
方法中修改注入的
LifestyleSingleton
对象,可能会遇到并发问题,但这与将其从容器中释放无关。

否,在使用组件之前释放组件是不合适的。Windsor跟踪嵌套组件的生存期,因此释放根组件通常会释放其子组件。我希望避免使用具有潜在无效状态的组件

因此,我最终采用了以下方式发布
命令

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);
                }
            }
        }
    }
}
A类
{
公共MyTypedFactory工厂{get;set;}
公共类B命令填充器{get;set;}
公共图书馆
{
List命令=new List();
尝试
{
CommandsOperator.Commands=命令;

对于(inti=0;使用try/finally块是个好主意。但是如果
CommandsPopulator.Bar()中的一些
调用失败?队列中已经存在的对象将永远不会被释放。我认为必须包装在
try
中的是
ClassA.Foo
的方法体,在
命令
声明之后一直到最后。然后需要第三个释放循环,如我在问题中所示。这个释放循环仍然放在中e> 最后
对于异常是不安全的:如果其中一个
Release
调用抛出,循环将退出,其余的命令将不会被释放。
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);
                }
            }
        }
    }
}