2015-12-04 26 views
5

vedo Simple Injector s' Contenitore ha questo methodIl Simple Injector ha un modo di registrarsi condizionale con la fabbrica di oggetti?

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

Ma voglio usare il diverso oggetto dello stesso implementazione per servizio diverso, così che cosa sovraccarico metodo ho bisogno sarebbe simile a questa

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

Ma il SimpleInjector non ce l'ha. Sto cercando di trovare i metodi dell'altro contenitore per registrare il creatore dell'istanza con le condizioni per il servizio. Ci sono altri modi in cui posso fare?

Oppure, è quello che sto cercando di fare non il buon design, quindi gli sviluppatori non lo implementano?

Modificato: Aggiunto esempio e la domanda più dettagliata.

Esempio

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") 

Dal codice sorgente di esempio, come posso registrarle per ottenere locatorForCSVFileScanner oggetto passato al costruttore CSVFileScanner quando CSVFileScanner sempre creato e locatorForXMLFileScanner oggetto passato al costruttore XMLFileScanner quando XMLFileScanner sempre creato ?

+0

"Voglio usare il diverso oggetto dello stesso implementazione per servizio diverso". Puoi riformulare la tua domanda? Non capisco cosa vuoi. – Steven

+0

@ Steven Ho modificato la domanda, cercando di spiegare cosa ho chiesto. – wrongite

risposta

7

Oppure, è quello che sto cercando di fare non il buon design, quindi gli sviluppatori non lo implementano?

Dopo aver visto il tuo esempio, devo concludere che potrebbe esserci un difetto di progettazione. Il problema principale del design è che sembra violare lo Liskov Substitution Principle (LSP). LSP è uno dei principi SOLID e afferma che le sottoclassi (o le implementazioni di interfacce) devono essere intercambiabili l'una con l'altra, senza intaccare il consumatore. Nell'applicazione, tuttavia, XMLFileScanner sembra interrompersi quando viene fornito con un file CSV.

Quindi da una prospettiva dell'LSP, questo significa che entrambe le implementazioni dello scanner di file meritano la propria astrazione. Una volta che darai la propria astrazione, il problema sparirà completamente.

Se tuttavia lo scambio dei file locator non ha alcun effetto sul funzionamento degli scanner di file (ad esempio perché non leggono, ma solo scrivono), LSP non viene violato e il design è corretto.

Se non è possibile modificare le astrazioni o LSP non viene violato, un'opzione è di registrare gli scanner di file utilizzando un delegato di fabbrica o semplicemente creando una volta come singleton. Questo ti dà il pieno controllo sulla composizione di quella parte del grafico dell'oggetto. Per esempio:

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

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

Ma la SimpleInjector non ce l'ha. Sto cercando di trovare i metodi dell'altro contenitore per registrare il creatore dell'istanza con le condizioni per il servizio. Ci sono altri modi in cui posso fare?

In questo modo è possibile utilizzare i metodi RegisterConditional, ma questa funzione è un po 'nascosta e ciò è intenzionale.Simple Injector tenta di promuovere la costruzione di grafici di oggetti che sono completamente noti nella fase di avvio e scoraggia la costruzione di grafici di oggetti in base alle condizioni di runtime. L'utilizzo di un delegato Func<TService> instanceCreator consente di creare condizioni di esecuzione ed è per questo che manca tale sovraccarico.

Il modo per fare questo però è la seguente:

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

Questa risposta ha reso la mia giornata. Supponendo che ognuno di quei 'CreateRegistration' non prende decisioni su quale oggetto dovrebbe tornare, c'è qualche svantaggio in questa tecnica? – vtortola

+0

@vtortola: Quando si chiama 'RegisterConditional' senza passare in un oggetto' Registration' creato manualmente, 'RegisterConditional' creerebbe internamente un'istanza' Registration'. Quindi entrambi i costrutti sono esattamente gli stessi. La differenza, naturalmente, è che chiamando 'CreateRegistration' consente di passare un delegato' instanceCreator'. – Steven