2012-05-02 2 views
8

Sto appena iniziando a conoscere IoC e Dipendenza iniezione. Sto pensando di fare un progetto MonoTouch e volevo usare TinyIoC ma volevo provarlo prima. Sto creando una fittizia app per la gestione delle carte di credito e sto avendo problemi con la configurazione di TinyIoC poiché ho implementazioni multiple della mia interfaccia. Questa è la mia app di prova.TinyIoC - Implementazioni multiple di interfaccia

Interfaccia:

public interface IPaymentProcessor 
{ 
    void ProcessPayment(string cardNumber); 
} 

due implementazioni dell'interfaccia:

VisaPaymentProcessor

public class VisaPaymentProcessor : IPaymentProcessor 
{ 
    public void ProcessPayment(string cardNumber) 
    { 
     if (cardNumber.Length != 13 && cardNumber.Length != 16) 
     { 
      new ArgumentException("Card Number isn't the correct length"); 
     } 

     // some code for processing payment 
    } 
} 

AmexPaymentProcessor

public class AmexPaymentProcessor : IPaymentProcessor 
{ 
    public void ProcessPayment(string cardNumber) 
    { 
     if (cardNumber.Length != 15) 
     { 
      new ArgumentException("Card Number isn't the correct length"); 
     } 

     // some code for processing the payment 
    } 
} 

Semplice. Ora ho una classe che accetta l'interfaccia come parametro nel costruttore ....

CreditCardProcessor

public class CreditCardProcessor 
{ 
    public IPaymentProcessor PaymentProcessor { get; set; } 

    public CreditCardProcessor(IPaymentProcessor processor) 
    { 
     this.PaymentProcessor = processor; 
    } 

    public void ProcessPayment(string creditCardNumber) 
    { 
     this.PaymentProcessor.ProcessPayment(creditCardNumber); 
    } 
} 

mia console app si presenta così ....

class Program 
{ 
    static void Main(string[] args) 
    { 
     TinyIoCContainer.Current.AutoRegister(); 

     var creditCardProcessor = TinyIoCContainer.Current.Resolve<CreditCardProcessor>(); 
     creditCardProcessor.ProcessPayment("123456789"); // 16 digits 
    } 
} 

Quindi sto cercando di capire come dire allo Resolve quale implementazione dell'interfaccia passare al costruttore. Se eseguo questo codice, utilizzerò sempre l'implementazione VisaPaymentProcessor.

Quindi, come posso fare a TinyIoC passare l'implementazione AmexPaymentProcessor al costruttore piuttosto che allo VisaPaymentProcessor (che sembra essere l'impostazione predefinita)?

risposta

7

Non ho usato TinyIoC me stesso, ma ho il sospetto che si desidera:

TinyIoCContainer.Current.Register(typeof(IPaymentProcessor), 
            typeof(AmexPaymentProcessor)); 

(Se si desidera utilizzare Amex.)

Ci sono vari altri Register sovraccarichi disponibili, tra cui uno che prende a nome da utilizzare, che può essere utile quando si risolve. Dipende davvero da ciò che stai cercando di ottenere, il che non è molto chiaro dalla domanda.

+0

Grazie. Ho aggiornato il post con la domanda. Sembra che VisaPaymentProcessor sia l'implementazione "predefinita" utilizzata da TinyIoC. Come posso ottenere che TinyIoC passi l'implementazione 'AmexPaymentProcessor' al costruttore. Mi dispiace per non essere chiaro. –

+0

@ Eclipsed4utoo: Okay - in tal caso, mi aspetto che la mia risposta lo copra :) –

+0

@JonSkeet si scusa per la mia mancanza di comprensione, ma come si risolve questo problema originale degli OP? Sembra che voglia essere in grado di risolvere condizionalmente le dipendenze registrate in fase di runtime. –

2

Non sono sicuro di cosa si stia cercando di ottenere qui, ma se si dispone di più implementazioni di un'interfaccia e si desidera una specifica, è necessario registrare ciascuna con un nome o utilizzare RegisterMultiple, che usa il nome del tipo per un nome, quindi risolvi usando quel nome e usalo insieme a NamedParameterOverloads per specificare quale vuoi.

Sembra più che si possa desiderare una specie di ProcessorFactory, o una facciata di qualche tipo, che prende una dipendenza da IEnumerable e fornisce/funge da facciata per l'implementazione corretta a seconda del numero passato.

+1

Ho letto questo su Windsor IoC e mi chiedevo se lo stesso vale per TinyIoC .... 'Ora quando" Risolvi "un'istanza di CreditCardProcessor, il contenitore guarda il costruttore e vede che ha bisogno di un IPaymentProcessor. Il contenitore cerca di vedere se quel tipo è registrato nel contenitore. Se lo è, il contenitore "Risolvi" quel tipo e quindi istanzia il processo CreditCardProcessor. In tal caso, come gestisce TinyIoC quando sono registrate due implementazioni per l'interfaccia? Sembra che scelga il primo tipo registrato usando "RegisterMultiple". –

+1

@ Eclipsed4utoo C'è sempre una sola registrazione "predefinita" per un'interfaccia (una senza nome), ed è quella che si ottiene se si prende una dipendenza da essa. Quando si utilizza AutoRegister quale di questi è "predefinito", non è garantito, quindi è necessario impostarlo da sé o registrarli tutti e estrarre il nome corretto. –

+0

Grazie Steven. L'unico modo che posso trovare per specificare l'implementazione corretta è utilizzare NamedParameterOverloads quando si risolve 'CreditCardProcessor'. Tuttavia, ciò sembrerebbe "hardcode" alla firma del costruttore in quanto avrei bisogno del NamedParametersOverload per abbinare la firma del costruttore. Se la funzione di costruzione cambia, NamedParametersOverload avrà esito negativo se non apporto le modifiche anche lì. Per me, questo tipo di sconfigge lo scopo di usare un IoC. Sono appena fuori dalla base? –

2

Qualcosa di simile in Global.ASax o voce di applicazione (Modificata per il tuo esempio)

 const string nameTrim = "paymentprocessor"; 
     var type = typeof(IPaymentProcessor); 
     AppDomain.CurrentDomain.GetAssemblies() 
      .SelectMany(s => s.GetTypes()) 
      .Where(x => type.IsAssignableFrom(x) && x.IsClass).ToList() 
      .ForEach(t => 
      { 
       var name = t.Name.ToLower(); 
       if (name.EndsWith(nameTrim)) 
        name = name.Substring(0, name.Length - nameTrim.Length); 

       TinyIoCContainer.Current.Register(type, t, name); 
      }); 

Essa trova Alla implementazioni di IPaymentProcessor e li registra con nomeclasse (-PaymentProcessor, se il nome di classe termina con PaymentProcessor)

Poi posso risolvere per esempio "AmexPaymentProcessor" con

 IPaymentProcessor handler; 
     if (TinyIoCContainer.Current.TryResolve("amex", out handler)) 
     { 
      response = handler.ProcessPayment(cardNumber); 
     }