Given the following code, how do I resolve the right SomeInstance in autofac?
public class BaseClass {} public class SubClass1 : BaseClass {} public class SubClass2 : BaseClass {} public interface IGenericInterface<T> where T : BaseClass {} public class SomeInstance1<T> : IGenericInterface<T> where T : SubClass1 public class SomeInstance2<T> : IGenericInterface<T> where T : SubClass2
I want to choose SomeInstance1 or 2 based on the type of of the generic on the sub classes.
So for example I have a collection of sub classes (SubClass1, 2....) and while iterating over them I want to choose the right SomeInstance class.
Autofac supports open generics. You can use the following code if generics type is known at compile time:
var builder = new ContainerBuilder(); builder.RegisterGeneric(typeof(SomeInstance1<>)) .As(typeof(IGenericInterface<>)); var container = builder.Build(); var instance1 = container.Resolve<IGenericInterface<SubClass1>>(); Assert.IsInstanceOfType(typeof(SomeInstance1<SubClass1>), instance1);
If type parameter is not known until runtime (which is likely your case if you want to iterate through collection of types) then you can build your type using MakeGenericType:
var typeInRuntime = typeof (SubClass1); var instance1 = container.Resolve(typeof(IGenericInterface<>).MakeGenericType(typeInRuntime));
Correction. You cannot call MakeGenericType from the Container. I solved the issue of instantiating Generics using the 'TYPE' as the parameter on the Resolve call. The builder is registered.
builder.RegisterGeneric(typeof (FakeRepository<>)).As(typeof (IRepository<>)).OnActivating(e => { var typeToLookup = e.Parameters.FirstOrDefault() as TypedParameter; if (typeToLookup != null) { var respositoryType = typeof (FakeRepository<>); Type[] typeArgs = {typeToLookup.Value.GetType()}; var genericType = respositoryType.MakeGenericType(typeArgs); var genericRepository = Activator.CreateInstance(genericType); e.ReplaceInstance(genericRepository); } });
Then the resolution happens like this, passing a TypedParameter to the Resolve. In this case I have a list of items (IItem) that are resolved that I want to create a repository for all of the items of that type.
var items = container.Resolve<IEnumerable<IItem<string>>>(); foreach (var item in items) { var repository = container.Resolve(typeof (IRepository<DataItemBase>), new TypedParameter(item.GetType(), item)); Assert.IsNotNull(repository); }
Thanks for your post it helped and I Hope this update helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With