Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resolving Generic Interface with Autofac

Tags:

c#

autofac

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.

like image 390
DownChapel Avatar asked Jul 27 '09 17:07

DownChapel


2 Answers

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)); 
like image 185
andrey.tsykunov Avatar answered Oct 17 '22 06:10

andrey.tsykunov


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.

like image 43
JeremyFromNaples Avatar answered Oct 17 '22 06:10

JeremyFromNaples