2009-10-06 9 views
6

La documentation indique que Autofac soutient génériques ouverts et je suis en mesure d'enregistrer et de résoudre dans un cas de base comme ceci:Autofac avec Open Generics et type spécifié au Runtime

Inscription:

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

Resolve:

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

Le code ci-dessus fonctionne très bien. Cependant, en supposant que je ne saurai pas le type prévu à IFlattener jusqu'à l'exécution, je veux faire quelque chose comme ceci:

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

Est-ce possible avec AutoFac? J'ai eu l'idée de ce qui suit à l'aide StructureMap:

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

J'essaie d'atteindre le même objectif décrit dans cet article.

Répondre

9

Ceci est certainement possible avec Autofac. Au « registre du temps », c'est ce que vous faites essentiellement:

  1. Enregistrez le type générique ouvert (PassThroughFlattener <>)
  2. Registre des types spécifiques (AddressFlattener)
  3. Enregistrer une méthode qui peut être utilisé pour résoudre un IFlattener basé sur un objet d'entrée

au "temps de détermination", vous allez faire:

  1. Resolve la méthode
  2. Appelez la méthode avec le paramètre d'entrée (s) pour résoudre la mise en œuvre de IFlattener

est ici un (je l'espère) l'échantillon de travail:

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

Merci pour la réponse rapide, ça marche! –

4

Si vous ne connaissez pas le type jusqu'à ce que runtime vous pouvez le construire en utilisant MakeGenericType:

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