2009-10-06 8 views
6

La documentazione afferma che Autofac supporta farmaci generici aperti e sono in grado di registrare e risolvere in un caso base in questo modo:Autofac con Open Generics e tipo specificato in fase di esecuzione

Registrazione:

builder.RegisterGeneric(typeof(PassThroughFlattener<>)) 
     .As(typeof(IFlattener<>)) 
     .ContainerScoped(); 

Resolve:

var flattener = _container.Resolve<IFlattener<Address>>(); 

Il codice sopra funziona perfettamente. Tuttavia, supponendo che non voglio conoscere il tipo fornite IFlattener fino al runtime, voglio fare qualcosa di simile:

object input = new Address(); 
var flattener = (IFlattener)_container.Resolve(typeof(IFlattener<>), new TypedParameter(typeof(IFlattener<>), input.GetType())); 

Questo è possibile con autofac? Ho avuto l'idea da quanto segue usando StructureMap:

http://structuremap.sourceforge.net/Generics.htm

Sto cercando di raggiungere lo stesso obiettivo descritto in questo articolo.

risposta

9

Questo è certamente possibile con Autofac. Al "registrare il tempo", questo è quello che fondamentalmente fa:

  1. registrare il tipo aperto generico (PassThroughFlattener <>)
  2. nessun tipi specifici (AddressFlattener)
  3. Registra un metodo che può essere utilizzato per risolvere un IFlattener basato su un oggetto di ingresso

Al "tempo risolvere", si farà:

  1. Resolve il metodo
  2. chiamata il metodo con il parametro di ingresso (s) per risolvere l'attuazione IFlattener

Ecco una (si spera) del campione di lavoro:

var openType = typeof(IFlattener<>); 

var builder = new ContainerBuilder(); 
builder.RegisterGeneric(typeof(PassThroughFlattener<>)).As(openType); 
builder.Register<AddressFlattener>().As<IFlattener<Address>>(); 
builder.Register<Func<object, IFlattener>>(context => theObject => 
    { 
     var concreteType = 
      openType.MakeGenericType(theObject.GetType()); 
      return (IFlattener) context.Resolve(concreteType, 
       new PositionalParameter(0, theObject)); 
    }); 
var c = builder.Build(); 

var factory = c.Resolve<Func<object, IFlattener>>(); 

var address = new Address(); 
var addressService = factory(address); 

Assert.That(addressService, Is.InstanceOfType(typeof(AddressFlattener))); 

var anything = "any other data"; 
var anyService = factory(anything); 

Assert.That(anyService, Is.InstanceOfType(typeof(PassThroughFlattener<string>))); 
+0

Grazie per la risposta rapida, che funziona! –

4

Se non sanno tipo fino runtime è possibile creare utilizzando MakeGenericType:

var addressFlattener = _container.Resolve(typeof(IFlattener<>).MakeGenericType(typeof(Address)));