2012-02-22 9 views
7

Can Castle Windsorは、文字列パラメータでフィルタリングされたコレクションを解決できますか?フィルタリングパラメータを使用して収集を解決するにはどうすればよいですか?

interface IViewFactory 
{ 
    IView[] GetAllViewsInRegion(string regionName); 
} 

私のアプリケーションは、領域をIView派生型のグループとして定義します。実行時に特定の領域を表示すると、その中のすべてのIView型のインスタンスを解決したいと考えています(a la Prism)。

キャッスルのTyped Factory Facility、ComponentModel Construction Contributors、Handler Selectorsで試してみましたが、キャッスルがアクセスできる方法で複数の型を文字列にマップする方法を理解できません。どの型を解決してコンテナに戻そうとするかを決定するときに、文字列をチェックするためにCastleを拡張します。

答えて

1

文字列による選択は厳密に必要ですか?代わりに、同じ「領域」内のすべてのIView実装にIViewから派生した専用インタフェースを実装することは可能でしょうか?次に、WindsorContainer.ResolveAll()(地域固有のIViewをTに渡す)を使用して問題の領域の実装を解決します(または、コレクションリゾルバの1つを使用してコンストラクタを実行できます)。

一般的に、ウィンザーでこのようなことをしようとすると、文字列ベースのソリューションに頼る前に、型システム(およびそのウィンザーのサポート)を使用するよう全力を尽くします。

アップデート:この場合、文字列による選択が必要であることを確認したので、私が見る最良の解決策は、IViewサービスを満たすカーネルのハンドラのリストを単純に検査し、領域(属性によって定義されます)は、私たちが望むものと一致し、それらの実装者を解決します。これはちょっとハックしているようですが、IViewFactory実装のコンテナへの直接参照があれば問題ありません。以下は、このソリューションを示すテストケースです。

[Test] 
    public void Test() 
    { 
     using (var factory = new ViewFactory()) 
     { 

      var regionOneViews = factory.GetAllViewsInRegion("One"); 
      Assert.That(regionOneViews, Is.Not.Null); 
      Assert.That(regionOneViews, Has.Length.EqualTo(2)); 
      Assert.That(regionOneViews, Has.Some.TypeOf<RegionOneA>()); 
      Assert.That(regionOneViews, Has.Some.TypeOf<RegionOneB>()); 

      var regionTwoViews = factory.GetAllViewsInRegion("Two"); 
      Assert.That(regionTwoViews, Is.Not.Null); 
      Assert.That(regionTwoViews, Has.Length.EqualTo(1)); 
      Assert.That(regionTwoViews, Has.Some.TypeOf<RegionTwoA>()); 
     } 
    } 
} 

public interface IViewFactory 
{ 
    IView[] GetAllViewsInRegion(string regionName); 
} 

public class ViewFactory : IViewFactory, IDisposable 
{ 
    private readonly WindsorContainer _container; 

    public ViewFactory() 
    { 
     _container = new WindsorContainer(); 
     _container.Register(
      Component.For<IView>().ImplementedBy<RegionOneA>(), 
      Component.For<IView>().ImplementedBy<RegionOneB>(), 
      Component.For<IView>().ImplementedBy<RegionTwoA>() 
      ); 
    } 

    public IView[] GetAllViewsInRegion(string regionName) 
    { 
     return _container.Kernel.GetHandlers(typeof (IView)) 
      .Where(h => IsInRegion(h.ComponentModel.Implementation, regionName)) 
      .Select(h => _container.Kernel.Resolve(h.ComponentModel.Name, typeof (IView)) as IView) 
      .ToArray(); 
    } 

    private bool IsInRegion(Type implementation, 
          string regionName) 
    { 
     var attr = 
      implementation.GetCustomAttributes(typeof (RegionAttribute), false).SingleOrDefault() as RegionAttribute; 
     return attr != null && attr.Name == regionName; 
    } 

    public void Dispose() 
    { 
     _container.Dispose(); 
    } 
} 

public interface IView {} 

[Region("One")] 
public class RegionOneA : IView {} 

[Region("One")] 
public class RegionOneB : IView {} 

[Region("Two")] 
public class RegionTwoA : IView {} 

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 
public class RegionAttribute : Attribute 
{ 
    private readonly string _name; 

    public RegionAttribute(string name) 
    { 
     _name = name; 
    } 

    public string Name 
    { 
     get { return _name; } 
    } 
} 
+0

私はあまりにも種類代わりの文字列キーを使用しようが、私は(RegionBehavior)で働いているプリズム拡張ポイントは、文字列で地域を関連付けたので、私は、文字列での選択の周りにどのような方法を参照することはできません。実際には、プリズムはその領域内のオブジェクトしか期待していないので、IViewインターフェースでさえ、私の人為的な単純化です。 [改訂1](http://stackoverflow.com/revisions/9394391/1)では、私は質問の文脈をたくさん与えましたが、人々を怖がらせていたと思います。 –

+0

一部の地域はプラグインで定義されています。私のクラスが、短い名前「 "I" + regionName + "View" '」を持つマーカインタフェースのためにロードされたアセンブリを検索しなければならない場合は、非常に複雑で遅くなります。 'ViewExport [RegionName =" MainRegion "]'のカスタム属性を持つクラスを装飾し、ウィンザーのHandlersFilter拡張ポイントのようなフィルタタイプを好むでしょう。 –

+0

さて、私はプリズムに精通していないので、文字列の選択が必要であることはわかりませんでした。私はこれのような何かが可能であるべきだと思う。私は今日余裕をもって何かを考え出すつもりです:-) –

関連する問題