Home > Mobile >  How do I use Runtime Type Arguments in scope.Resolve<Service<T>>().Method1() in Autofac?
How do I use Runtime Type Arguments in scope.Resolve<Service<T>>().Method1() in Autofac?

Time:10-19

I have a generic service like below:

public interface ISyncedDataService<T> where T : BaseDBModel
    {
        Task<int> SaveItem(T item);
        Task<int> InsertAllItems(List<T> items);
        Task<List<T>> GetItems();
        Task<T> GetItem(long primaryKey);
        Task<int> DeleteItem(T item);
    }

And have a bunch of classes T1, T2, T3, T4.. T20 which are inherited from BaseDBModel.

I am using Autofac for invoking services like below:

using var scope = App.Container.BeginLifetimeScope(); //Container is Autofac.IContainer

var items = await scope.Resolve<ISyncedDataService<T1>>().GetItems(); //T1 inherits BaseDBModel

How do I invoke the GetItems() if the type T1...T20 is known only on run time? Currently I am using an if-else chain to make it simple and fast. But curios on how I can do that dynamically (reflections?)

Edit: When using reflections, the challenge is when trying to dynamically get the MethodInfo for an extension method which is also a generic method.

CodePudding user response:

You cannot resolve type argument in a generic class using reflection.

But to invoke a method in a specific class, this answer which uses reflection might help.

How do I use reflection to call a generic method?

If you just want to register a generic interface as a generic class.

  `builder.RegisterGeneric(typeof(YourGenericClass<>)).As(typeof(YourGenericInterface<>))`

is the code using autofac.

CodePudding user response:

If you dont have a bound generic type with you at runtime, then you run into this if-else type checking pattern. I am not sure if this has got much to do with Autofac. At the risk of sounding obvious, you could resolve this calling the non-generic Resolve method which returns an object.

object foo = componentContext.Resolve(type);

This is as generic as it gets.

An additional thing you can do is cast the object back to ISyncedDataService<BaseDBModel> but this only works if your interface is covariant. Declare it like:

interface ISyncedDataService<out T> where T : BaseDBModel

// and then
var foo = (ISyncedDataService<BaseDBModel>)componentContext.Resolve(type);

Again, whether covariance makes sense for your interface is something you have to decide.


Some caveats.. Hope you are not using the service locator anti-pattern here. Also take care of the lifetime of scope there, you seem to dispose the scope in the method you resolve the dependency. That should by default terminate the dependency along with the scope. Hope the dependencies are registered to be longer lived.

  • Related