5

は私がSimple Injectorのコンテナがこのmethodシンプルインジェクタにオブジェクトファクトリに条件を登録する方法がありますか?

public void RegisterConditional<TService, TImplementation>(
    Predicate<PredicateContext> predicate 
) 

持って見しかし、私は別のサービスのために同じ実装の異なるオブジェクトを使用したいので、私はこの

public void RegisterConditional<TService>(
    Func<TService> instanceCreator, 
    Predicate<PredicateContext> predicate 
) 
のようになります。必要なメソッドをオーバーロードされたものを

しかし、SimpleInjectorはそれを持っていません。私はインスタンスの作成者にサービスの条件を登録するための他のコンテナのメソッドを見つけることを試みています。 他にもできることはありますか?

または、私は良いデザインではないと考えているので、開発者は実装していませんか?

編集:例と詳細な質問を追加しました。

CSVFileScannerが作成なったときとXMLFileScannerコンストラクタに渡さlocatorForXMLFileScannerオブジェクトがXMLFileScannerが作成なったときに、私はCSVFileScannerコンストラクタに渡さlocatorForCSVFileScannerオブジェクトを取得するためにそれらを登録する方法の例のソースコードから

class CSVFileScanner 
{ 
    public CSVFileScanner(IFileLocator fileLocator) { } 
} 

class XMLFileScanner 
{ 
    public XMLFileScanner(IFileLocator fileLocator) { } 
} 

class DefaultLogFileLocator: ILogFileLocator 
{ 
    public DefaultLogFileLocator(string directoryPath, string searchPattern) { } 
} 

var locatorForCSVFileScanner = new DefaultLogFileLocator("C:\CSVLogDir", "*.csv") 
var locatorForXMLFileScanner = new DefaultLogFileLocator("C:\XMLLogDir", "*.xml") 

、 ?

+0

は「私は別のサービスのために同じ実装の異なるオブジェクトを使用したいです」。あなたはあなたの質問を言い換えることができますか?私はあなたが何を望んでいるのか理解していません。 – Steven

+0

@スティーブン私は質問した内容を説明しようとしました。 – wrongite

答えて

7

または、私は良いデザインではないと考えているので、開発者は実装していませんか?

あなたの例を見てから、私は設計上の欠陥があるかもしれないと結論づけなければなりません。デザインの主な問題は、Liskov Substitution Principle(LSP)に違反しているようです。 LSPは、SOLID原則の1つであり、サブクラス(またはインタフェースの実装)は、消費者に影響を与えることなく相互に交換可能であるべきであると述べている。あなたのアプリケーションでは、XMLFileScannerは、CSVファイルが提供されているときに壊れているようです。

LSPの観点から見ると、これは両方のファイルスキャナ実装が独自の抽象化を必要とすることを意味します。両方を自分の抽象化すると、問題は完全に消え去ります。

ただし、ファイルロケータをスワップしてもファイルスキャナの動作に影響がない場合(たとえば、読み込みが行われずに書き込みが行われるなど)、LSPに違反はなく、デザインは正常です。

アブストラクションを変更することができない場合や、LSPに違反していない場合は、ファクトリデリゲートを使用してファイルスキャナを登録するか、またはシングルトンとして一度だけ作成することでオプションを登録できます。これにより、オブジェクトグラフのその部分の構成を完全に制御できます。例えば:

container.RegisterSingleton<CSVFileScanner>(
    new CSVFileScanner(new DefaultLogFileLocator("C:\CSVLogDir", "*.csv"))); 

container.RegisterSingleton<XMLFileScanner>(
    new XMLFileScanner(new DefaultLogFileLocator("C:\XMLLogDir", "*.xml"))); 

しかしSimpleInjectorはそれを持っていません。私はインスタンスの作成者にサービスの条件を登録するための他のコンテナのメソッドを見つけることを試みています。それ以外の方法はありますか?

実際にRegisterConditionalメソッドを使用してこれを行うことはできますが、この機能は少し隠されています。これは意図的なものです。Simple Injectorは、スタートアップ段階で完全に知られているオブジェクトグラフの構築を促進し、実行時の条件に基づいてオブジェクトグラフを作成することを防ぎます。 Func<TService> instanceCreatorデリゲートを使用すると、実行時の条件が作成されるため、そのようなオーバーロードが欠落しています。次のように

しかし、これを行う方法は次のとおりです。

var csv = Lifestyle.Singleton.CreateRegistration<IFileLocator>(
    () => new DefaultLogFileLocator("C:\\CSVLogDir", "*.csv"), container); 

var xml = Lifestyle.Singleton.CreateRegistration<IFileLocator>(
    () => new DefaultLogFileLocator("C:\\XMLLogDir", "*.csv"), container); 

container.RegisterConditional(typeof(IFileLocator), csv, WhenInjectedInto<CSVFileScanner>); 
container.RegisterConditional(typeof(IFileLocator), xml, WhenInjectedInto<XMLFileScanner>); 

// Helper method. 
static bool WhenInjectedInto<T>(PredicateContext c) => 
    c.Consumer.ImplementationType == typeof(T); 
+0

この回答は私の一日にしました。それらの 'CreateRegistration'のそれぞれが返すべきオブジェクトについて決定を下さないと仮定すると、このテクニックには何らかの欠点がありますか? – vtortola

+0

@vtortola:手動で作成した 'Registration'オブジェクトを渡さずに' RegisterConditional'を呼び出すと、 'RegisterConditional'は内部的に' Registration'インスタンスを作成します。したがって、両方の構造はまったく同じです。違いはもちろん、 'CreateRegistration'を呼び出すと' instanceCreator'デリゲートを渡すことができます。 – Steven

関連する問題