Ian Dillon Ian Dillon - 24 days ago 7
C# Question

How to invoke a method accepting linq expression arguments

hi this is my method which exists as part of a generic entity framework repository class.

public IList<T> GetAll(params Expression<Func<T, object>>[] navigationProperties)
{
List<T> list;

IQueryable<T> dbQuery = Context.Set<T>();

//Apply eager loading
foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
dbQuery = dbQuery.Include<T, object>(navigationProperty);

list = dbQuery
.AsNoTracking()
.ToList<T>();
return list;
}


I need to call the method via reflection and this is what I have done so far.

using (var ctx = (DbContext)Activator.CreateInstance(dbContextType))
{
ctx.Configuration.LazyLoadingEnabled = false;

var curEntityPI = ctx.GetType().GetProperties().Where(pr => pr.Name == "Worker").First();
var curEntityType = curEntityPI.PropertyType.GetGenericArguments().First();
var set = ctx.Set(curEntityType);
Type generic = typeof(DataAccess.Repository.EF.dEfDataRepository<,>);
Type[] typeArgs = {curEntityType, dbContextType};
Type constructed = generic.MakeGenericType(typeArgs);
MethodInfo methodInfo = constructed.GetMethod("GetAll");

object repositoryInstance = Activator.CreateInstance(constructed, new object[] { ctx });
var result = methodInfo.Invoke(repositoryInstance,new object[] { });
}


I know I need to change the parameter array in methodInfo.Invoke, but for test purposes say it was just an empty linq expression or the equivalent of this when called statically ..

WorkerRepository workerRepositoryInstance = new
WorkerRepository<Worker,MyDbContext>(ctx);
List<Worker> workers = workerRepositoryInstance.GetAll().ToList();


How would I supply the correct parameter in methodInfo.Invoke()

I am doing this because I need to work with a dbcontext and entities which are in an external dll and can't add a reference to this in my application project. My application needs to able reference the 'satellite' assembly in a way that different deployments of the application can access different versions of the data provider dll.

Thanks a lot for your help.

Answer

If I understand correctly, you need to create dynamically an empty array of Expression<Func<T, object>>.

You can use Array.CreateInstance method for that:

var navigationPropertyType = typeof(Expression<>).MakeGenericType(
    typeof(Func<,>).MakeGenericType(curEntityType, typeof(object)));

var navigationProperties = Array.CreateInstance(navigationPropertyType, 0);

var result = methodInfo.Invoke(repositoryInstance, new object[] { navigationProperties });