6

私は、単一メソッドのインターフェイスの代わりに名前付きのデリゲートを使用して実験してきました。Castle Windsorに静的クロージャを登録する簡単な方法はありますか?

public interface IProductSource 
{ 
    IEnumerable<Product> GetProducts(); 
} 
public class DataContextProductSource : IProductSource 
{ 
    private readonly DataContext _DataContext; 
    public DataContextProductSource(DataContext dataContext) 
    { 
     if (dataContext == null) throw new ArgumentNullException("dataContext"); 
     _DataContext = dataContext; 
    } 
    public IEnumerable<Product> GetProducts() 
    { 
     return _DataContext.Products.AsEnumerable(); 
    } 
} 

へ:

public delegate IEnumerable<Product> DGetProducts(); 
public static class DataContextFunctions 
{ 
    public DGetProducts GetProducts(DataContext dataContext) 
    { 
     if (dataContext == null) throw new ArgumentNullException("dataContext"); 
     return() => dataContext.Products.AsEnumerable(); 
    } 
} 

これは基本的に事実を利用している我々は(ケースを誇張しないように削除いくつかの改行)から行くことができるので、これは、コードサイズのためのいくつかの利点を持っています一度あなたが依存性注入で十分に遠くに行くと、多くのクラスは閉鎖以上になりません。これらのクラスはlambdaを返す関数に置き換えることができます。関連する関数(可変状態をカプセル化する必要はなく、 "標準"依存関係注入でクラスを使用して表現される)は、静的クラス(またはVBの用語では "モジュール")にロールアップできます。 。

これはすべてうまくいいですが、私はCastle Windsorでこれらの静的メソッドを登録する最良の方法を見つけるのが難しいです。依存関係のないメソッドは簡単です:

Component.For<DGetIntegers>().Instance(Integers.GetOneToTen) 

しかし、上記のDataContextFunctions.GetProductsにはいくつかの依存関係があります。私はこれを登録するために見つけた最良の方法は次のとおりです。

Component.For<DGetProducts>().UsingFactoryMethod(
    kernel => DataContextFunctions.GetProducts(kernel.Resolve<DataContext>()) 

これは非常に冗長取得し、明らかに種類のポイントを少し倒し各依存関係のためにカーネルを直接依頼することができました。コンテナが必要とするすべての静的情報が利用可能なので、これを行うことが可能であるはずです。

Castle Windsor(またはその他のコンテナ)はこれを行うための簡単な方法がありますか、技術的な問題が発生しているのか、あまりにも隙間のあるユースケースです含まれている?

答えて

4

を。私はあなたがカスタムアクティベータを使ってこれを非常に簡単に行うことができると思います。

+0

ありがとう、Krzysztof。私はいつかそれを試し、結果を報告します。良い場所を始めるためのリンクはありますか? – ninjeff

+0

@ninjeffもしあなたが2.5.xであれば、ドキュメンテーションはあなたがdocs.castleproject.org/(S(hucszcu5ilznbv45fvrim355))/を始めなければなりません。もしあなたが3.0ベータ版であれば、コンセプトはまだありますが、APIの変更があります同じ。ドコが完璧でない場合は私に教えてください –

+0

私はこれを働かせることができました。私は1時間で自分の答えでリンクと説明を投稿します(私のような低カルマのユーザーは8時間以内に自分の質問に答えることはできません)。 – ninjeff

10

短い答え

あなたはDIコンテナ(城ウィンザー)が機能構図を実行しようとしているが、それは実際にオブジェクト構図をターゲットにしています。それはちょうどあなたに多くの摩擦を与えるつもりです。私の推測では、あなたは他のコンテナで同じ経験をするでしょう。

DIコンテナは、オブジェクト指向の概念、特にSOLIDを中心に設計されています。コンストラクターインジェクションやオートワイヤリングなどの固有の理解を持って設計されているため、これらの原則ではうまく機能します。

もっと機能的なアプローチでは何も問題はありませんが、オブジェクトコンポジションの代わりに関数コンポジションを使ってDIコンテナを見てきました。

ロング答えは

DIのための一般的な原則としてデリゲートを使用することは、理由のカップルのための(少なくとも.NETに)静的に型付けされた言語の問題となる傾向があります。概念的には、delegate can be considered as an anonymous Role Interface以降、このアプローチには何も問題はありません。しかし、タイプのあいまいさのために扱いにくくなる傾向があります。

通常私が見る最も一般的なアプローチは、Func<T>,Action<T>などのBCL組み込みのデリゲートを使用することです。しかし、Func<string>に依存する多くの異なる消費者がいるかもしれません。その場合、消費者がFunc<string>を必要とするだけで、同じ役割の代理人を必要とするわけではありません。代理人でDIを機械的に使用する可能性はありますが、代理人はアプリケーションロールを非表示にします。ロールは消え、メカニックだけが残る。

あなたは、その後、OPで示唆されているように、このデリゲートによって示唆されているように、各ロールのカスタムデリゲートを定義することができます。あなたはそのルートを取る場合

public delegate IEnumerable<Product> DGetProducts(); 

をしかし、その後、何も得られません。 「ロールデリゲート」は、各ロールに対してまだ定義されていなければなりません。同様のインタフェースを定義することをコントラストとのみ保存が角括弧のカップルと明示的なメソッドの定義であることそれは明らかである:

public interface IProductSource { IEnumerable<Product> GetProducts(); } 

多くのオーバーヘッド(もしあれば)ではありません。

また、この議論を見てみたいことがあります。興味深いアプローチをだhttp://thorstenlorenz.wordpress.com/2011/07/23/dependency-injection-is-dead-long-live-verbs/

+0

返信いただきありがとうございます。私は実際には完全に機能的なアプローチを試みるのではなく、ハイブリッドなアプローチを試しています。関数を使って、さまざまなコンセプトのオブジェクトとオブジェクトの相互作用の程度を見極めようとしています。 – ninjeff

+0

インターフェイスのオーバーヘッドに関しては、インターフェイス自体ではなく実装クラスの長さが長くなります。 – ninjeff

1

Krzysztofの指針に基づいて、これを処理するカスタムアクティベータを書くことができました。ソースはgithubです。

(問題の例以下)は、このような

レジスタ静的委譲:

container.Register(Component. 
    For<DGetProducts>(). 
    ImplementedBy(typeof(DataContextFunctions)). 
    Named("GetProducts"). 
    Activator<StaticDelegateActivator>()); 

コードは、主DefaultComponentActivatorの書き換えです。ウィンザーのソースコードからコピーして貼り付ける必要がありました。内部にあるので、DependencyTrackingScopeをコピーしてください。

テストプロジェクトの単一の「テスト」は、単一のユースケースのみをカバーします。私はプロキシのようなより高度なシナリオではうまくいくとは思わない。

私はKrzysztofの答えを受け入れました。その指針が解決策につながって以来です。

関連する問題