我正在使用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调用。这些调用必须在交易完成后不在交易期间进行。
答案 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的对象,或者异常发生的可能性非常低。