2009-10-06 14 views
6

Dokumentacja wskazuje, że Autofac wspiera otwarte rodzajowych i jestem w stanie zarejestrować i rozwiązać w podstawowej przypadku tak:Autofac z Open rodzajowych i typu określonego w Runtime

Rejestracja:

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

Resolve:

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

Powyższy kod działa dobrze. Jednak zakładając, że nie będzie znać rodzaj przekazywanych IFlattener aż wykonywania, chcę zrobić coś takiego:

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

Czy to możliwe AutoFac? Wpadłem na pomysł z poniższego przy użyciu StructureMap:

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

próbuję osiągnąć ten sam cel opisanej w tym artykule.

Odpowiedz

9

Jest to z pewnością możliwe dzięki Autofac. Na „zarejestrować czas”, to jest to, czego w zasadzie zrobić:

  1. Zarejestruj otwartego typu rodzajowego (PassThroughFlattener <>)
  2. rejestrować żadnych konkretnych typów (AddressFlattener)
  3. zarejestrować metody, które mogą być wykorzystane do rozwiązać IFlattener oparciu o obiektu wejściowego

w "czasie resolve", zrobisz:

  1. rozwiązać metoda
  2. wywołać metodę z parametrem wejściowym (S), aby rozwiązać realizacja IFlattener

Oto (mamy nadzieję) próbka robocza:

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

Dziękuję za szybką reakcję, która działa! –

4

Jeśli nie wiesz, rodzaj aż środowisko wykonawcze można zbudować za pomocą MakeGenericType:

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