2011-07-21 6 views
12

私は、これは広告nauseum議論されている知っている...しかし、私はウィンザーが一時IDisposableをオブジェクトを追跡している方法で問題が発生しました。城ウィンザー過渡使い捨て

私はウィンザーは私IDiposablesを管理させることの利点を理解し...しかし、私はそれを好きではありません。

私が使用してブロック内の私のコンポーネントをラップしたい場合はどうなりますか?コーダーは、リソースが使用ブロックの最後でクリーンアップされるという仮定を立てます。間違った - Disposeが呼び出されますが、Windsorは明示的に解放されるまでインスタンスを保持します。これは私が何をやっているか知っているので、私にとってはうまくやっています...しかし、クラスをコーディングし、IDisposableを他のIDisposableが通常使用されるように使用する別の開発者はどうですか?

using(factory.CreateInstance()) 
{ 
    .... 
} 

よりも、私にはより明確になります。本当に私のインスタンスを配置し、GCのためにそれらを対象と持つために

MyDisposable instance; 
try 
{ 
    instance = factory.GetInstance(); 
} 
finally 
{ 
    factory.Release(instance); 
} 

、私はWindsorContainerを参照するか、リリースを公開して、型指定されたファクトリを使用する必要があります方法。つまり、IDisposableコンポーネントを使用する唯一の許容される方法は、型付きのファクトリを使用することです。私の意見では、これは良いことではありません。誰かが既存のコンポーネントにIDisposableインターフェイスを追加するとどうなりますか? コンポーネントを注入することを期待するすべての場所を変更する必要があります。それは私の意見では本当に悪いです。 (非DIシナリオでは、Disposeも呼び出すように変更する必要がありますが、ウィンザーでは、すべての場所で型付きのファクトリを使用するように変更する必要があります。これはずっと大きな変更です)。

[OK]を、十分に公正、私はカスタムReleasePolicy権を使用することができますか?これはどう?

public class CustomComponentsReleasePolicy : AllComponentsReleasePolicy 
{ 
    public override void Track(object instance, Burden burden) 
    { 
     if (burden.Model.LifestyleType == LifestyleType.Pooled) 
      base.Track(instance, burden); 
    } 
} 

いいえ、私のIDisposable Transientコンポーネントは現在GCになります。

私は私のクラスは、タイプの多くのインスタンスを生成することができますので、TypedFactoryを使用したい場合は?

public interface IMyFactory 
{ 
    MyDisposable GetInstance(); 
    void Release(MyDisposable instance); 
} 

[Singleton] 
public class TestClass 
{ 
    public TestClass(IMyFactory factory) { } 
} 

[OK]をMyDisposableが追跡されていないので、まあ、1のために、工場出荷時にリリースを呼び出すと、MyDisposable上)廃棄する(呼び出すために何もしません....

どのように私は、これらの困難を克服することができますか?

ありがとうございました。

+1

私はこの –

+0

についてのブログにする必要がありますだと思いますありがとう。私はそれを読むよ:) – Jeff

答えて

10

まず第一に、どのようにあなたが作成していないオブジェクトに関連付けられたdecommisionの懸念を知っていますか?オブジェクトを自分で作成していないため、オブジェクトの作成を制御できません(工場がこれを行いました)。 iocの解決と消費者の処分を組み合わせると(factory.Releaseの代わりに.Disposeを呼び出す)、オブジェクトの作成方法を知っているにもかかわらず、オブジェクト自体を作成しなかったという要件を導入しています。次の例を考えてみましょう:複雑になることが、私は簡単な方法を私は表示されません

「コンポーネント」は、コンテナを通じて解決するものですが、あなたは運用停止の上に示されているように、自分の

public class Component : IDisposable 
{ 
    private readonly IAmSomething _something; 

    public Component(IAmSomething something) 
    { 
     _something = something; 
    } 

    public void Dispose() 
    { 
     // Problem 1: the component doesnt know that an implementation of IAmSomething might be disposable 
     // Problem 2: the component did not create "something" so it does not have the right to dispose it 
     // Problem 3: What if an implementation of "something" has a depenency on a disposable instance deep down in its object graph? 

     // this is just bad.. 
     IDisposable disposable = _something as IDisposable; 

     if (disposable != null) 
      disposable.Dispose(); 

    } 
} 

public interface IAmSomething 
{ 

} 

public class SomethingA : IAmSomething 
{ 

} 

public class SomethingB : IAmSomething, IDisposable 
{ 
    public void Dispose() 
    { 
    } 
} 

を処分したいです私はこれをうまくやってくれます。あなたのコードベースがサービスロケータのアンチパターン(http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/)で覆われている場合は、これがどのように問題になるかを見ることができます(私はあなたがコードであると言っているわけではありません)。

using(factory.CreateInstance()) 
{ 
    .... 
} 

よりも、私にはより明確に見えません:あなたはそれを省略した場合、/トライ私の視点からのように、何のコンパイル時のエラーを使用して文が、慣習がある...

まあ最終的にリリースはもう少し慣習に過ぎませんが、少し冗長です。あなたは、たとえばなど、ヘルパーを作成することでのtry /を最終的に短縮することができます:

[TestFixture] 
public class SomeCastleTests 
{ 
    [Test] 
    public void Example() 
    { 
     var container = new WindsorContainer(); 

     // you would of course use a typed factory instead in real word 

     using (var usage = new ComponentUsage<IAmSomething>(container.Resolve<IAmSomething>, container.Release)) 
     { 
      // use.. 
      usage.Component 
     } 
    } 
} 

public class ComponentUsage<T> : IDisposable where T : class 
{ 
    private Func<T> _create; 
    private Action<T> _release; 

    private T _instance; 

    public ComponentUsage(Func<T> create, Action<T> release) 
    { 
     _create = create; 
     _release = release; 
    } 

    public T Component 
    { 
     get 
     { 
      if (_instance == null) 
       _instance = _create(); 

      return _instance; 
     } 
    } 

    public void Dispose() 
    { 
     if (_instance != null) 
     { 
      _release(_instance); 
      _instance = null; 
     } 
    } 
} 

これは私の意見では、良いではありません...何誰かが既存のコンポーネントにIDisposableを インターフェイスを追加しますか? が注入されると予想されるすべての場所を変更する必要があります。

私はこの声明を理解していません。どのようにコンポーネントがリリースされ、必要なときに別の問題になるか、コンポーネントがコンストラクタ依存として提供されている場合、IDisposableを追加しても何も変更されません。コンストラクタを介して依存関係を取得したクラスはそれを作成しなかったため、それを解放する必要はありません。

0

ピギーバックとして、オブジェクトを解放するインターセプタを作成することで、言及した他のいくつかの点を解決できます。私は仕事の懸念の単位のためにこれを行う。インターセプタは、次のようになります。

public class UnitOfWorkReleaseOnDispose : IInterceptor 
{ 
    private readonly IUnitOfWorkFactory unitOfWorkFactory; 

    public UnitOfWorkReleaseOnDispose(IUnitOfWorkFactory unitOfWorkFactory) 
    { 
     this.unitOfWorkFactory = unitOfWorkFactory; 
    } 

    public void Intercept(IInvocation invocation) 
    { 
     invocation.Proceed(); 
     this.unitOfWorkFactory.DestroyUnitOfWork((IUnitOfWork)invocation.Proxy); 
    } 
} 

私の登録コードは次のようになります。

  Component.For<IUnitOfWork>() 
       .ImplementedBy<TransactionalUnitOfWork>() 
       .LifestyleTransient() 
       .Interceptors<UnitOfWorkReleaseOnDispose>() 
        .Proxy.Hook(h => h.Service<InterfaceMethodsOnlyProxyGenerationHook<IDisposable>>()) 

プロキシフックは、私が唯一IDiposableインタフェースのメソッドプロキシにしたいと言っているだけあります。そのクラスは次のようになります。

私は私が使用しているフックのオーバーロードを使用していますので、また、登録されている必要があり
public class InterfaceMethodsOnlyProxyGenerationHook<TInterface> : IProxyGenerationHook 
{ 
    public void MethodsInspected() 
    { 

    } 

    public void NonProxyableMemberNotification(Type type, System.Reflection.MemberInfo memberInfo) 
    { 

    } 

    public bool ShouldInterceptMethod(Type type, System.Reflection.MethodInfo methodInfo) 
    { 
     return typeof(TInterface) == type; 
    } 
} 

  Component.For<IProxyGenerationHook>() 
       .ImplementedBy<InterfaceMethodsOnlyProxyGenerationHook<IDisposable>>() 
       .LifestyleSingleton() 
関連する問題