I am trying to build a utility method that will generically load entitycollections using Reflection. The idea is that a programmer using the utility can specify any type of entity and this method will discover the correct EntityQuery and the load the context with what they requested. So, I have collected the Entity type and Where clause from the user, now I am trying to figure out how to invoke the method. Here is what I have:
public void Handle(LoadEntityQuery loadQuery, Action<LoadEntityQueryResult> reply)
{
foreach (var entry in loadQuery.Entities)
{
Type entityType = entry.Key;
Type _contextType = EmployeeJobsContext.Instance.GetType();
MethodInfo _methodInfo = (from x in _contextType.GetMethods()
where x.ReturnType.BaseType == typeof(EntityQuery)
from y in x.ReturnType.GetGenericArguments()
where y == entityType
select x).FirstOrDefault();
if (_methodInfo != null)
{
var query = _methodInfo.Invoke(EmployeeJobsContext.Instance, null);
var _loadMethods = from x in _contextType.GetMethods()
where x.Name == "Load" &&
x.GetParameters().Length == 3
select x;
MethodInfo _loadMethod = null;
if (_loadMethods != null)
{
foreach (MethodInfo item in _loadMethods)
{
ParameterInfo[] _paramInfo = item.GetParameters();
if (_paramInfo[0].ParameterType.BaseType == typeof(EntityQuery) &&
_paramInfo[1].ParameterType.IsGenericType &&
_paramInfo[1].ParameterType.GetGenericArguments().Length == 1 &&
_paramInfo[1].ParameterType.GetGenericArguments()[0].BaseType == typeof(LoadOperation) &&
_paramInfo[2].ParameterType == typeof(object))
{
_loadMethod = item;
break;
}
}
}
MethodInfo _loadOpMethod = this.GetType().GetMethod("LoadOperationResult");
Delegate d = Delegate.CreateDelegate(typeof(LoadOpDel), _loadOpMethod);
if (_loadMethod != null)
{
object [] _params = new object[3];
_params[0] = query;
_params[1] = d;
_params[2] = null;
_loadMethod = _loadMethod.MakeGenericMethod(entityType);
_loadMethod.Invoke(_context, _params);
}
}
}
}
public delegate void LoadOpDel(LoadOperation loadOp);
public void LoadOperationResult (LoadOperation loadOp)
{
if (loadOp.HasError == true)
{
//reply(new LoadEntityQueryResult { Error = loadOp.Error.Message });
loadOp.MarkErrorAsHandled();
}
}
The foreach loop is iterating a Dictionary>>, where the Key is an Entity type and the value is a Where clause. The first part of code is finding the correct EntityQuery method and invoking it to get the actual query. It then discovers the correct Load overload (I know, likely there is a better way to find the method 🙂 ) This portion of the code works correctly, I am able to discover the correct EntityQuery and the Load method.
For the LoadOperation, I want to use the LoadOperationResult as my delegate method. When I try to run this code however, I receive an exception stating that the delegate type and the method type signatures do not match. I am pretty sure my signature is correct because if I was to call Load directly and pass the function name as the callback normally, this code would execute properly. I am fairly familiar with reflective programming, however throwing Generics and Action callbacks into the mix is a bit above my level at this point. I’m at a loss as to what I am doing wrong, does anyone have any pointers for me? Am I way off? Thanks for your help!!
Jason
I found that I did not need to use reflection to invoke the Load method (negating the need for the delegate), instead I call Load directly by creating a generic method based on Entity type. Here is what I came up with for anyone interested:
The handler for the Load operation watches for the last entity to finish loading, then responds to the client that loading is complete (with any errors, should they occur).