1

私は Windsor 3.1.0 を使用しており、 Typed FactoryLifestyleTransientを使用してコンポーネントをインスタンス化しています。参照ページで述べられているように、ファクトリから取得したすべてのオブジェクトを解放する必要があります。しかし、私はこのようなシナリオにいます

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 呼び出しの 1 つがスローされた場合、残りのオブジェクトは解放されず、メモリ リークが発生します (これが発生してはならないことはわかっていますが、この種のものから防御しようとしています)。

MyTransientCommandで作成した直後にリリースしても大丈夫ClassB.Barですか?ClassA.Fooコマンドオブジェクトのコレクションへの参照を保持しているため、メソッドが戻るまでGCによって解放されません。

WCF クライアント呼び出しを行い、WCF クライアントが Windsor でセットアップされている場合、リリースMyTransientCommandしても問題ありませんか? またはより一般的には、Windsor が提供する他のコンポーネントを使用する場合は?ClassB.BarMyTransientCommand.ExecuteMyTransientCommand.Execute

PS問題のコードは人工的で不自然に見えますが、そうです。これは、アルゴリズムに副作用が必要なためです。トランザクション内でデータベース内のデータの状態を変更すると、状況によっては WCF 呼び出しが発生する必要があります。これらの呼び出しは、トランザクション中ではなく、トランザクションが完了した後に行う必要があります。

4

2 に答える 2

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そうすれば、コマンドの使用時または実行時に例外が発生した場合でも、すべてのコマンドが解放されると確信しています。Releaseまた、各コマンドは、例外がスローされてループが中断されるのを防ぐために、try/catchブロックで解放されます。

うまくいけば、Windsorは、Typed Factoryでオブジェクトを解放するためのスローなしのセマンティクスに従うか、例外が発生する可能性が非常に低くなります。

于 2012-11-15T17:03:28.730 に答える
0

通常、オブジェクトを作成/注入したクラスに依存してオブジェクトを解放しますが、説明した方法でオブジェクトを解放しても問題は発生しません。リリースコードをfinally.

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

少し拡張するために、Castle は必要なすべての依存関係を注入します (工場が正しくセットアップされている限り)。コンテナーからオブジェクトを解放すると、単にそのインスタンスが解放されます。メソッドで挿入されたLifestyleSingletonオブジェクトを変更すると、同時実行の問題が発生する可能性がありますExecute()が、コンテナーからの解放とは関係ありません。

于 2012-11-14T03:30:48.740 に答える