So, experimenting with expression trees a bit. Here is the idea: I want to return a Func<long, byte?, object>
object. Depending on the type I want to use the function on, I'll have one of two methods to use: LoadById(long, byte?)
or LoadByID(long)
. Both return an object. So i'm trying to do the following: depending on whether the type implements a certain interface, I use either classToUseFunctionOn.LoadById(long, byte?)
or classToUseFunctionOn.LoadByID(long)
. So, basically I want to have the following code returned if it implements the interface: (long id, byte? options) => new TestFacade().LoadById(id, options) and (long id, byte? options) => new TestFacade().LoadByID(id). I'm just not sure how to do it. It goes wrong on the last few lines. The Lambda call states the amount of parameters is incorrect. Below is the code I have so far:
private static Func GetDataExtractorForTypeWithId(Type type)
{
var paramId = Expression.Parameter(typeof(long), "id");
ParameterExpression paramOptions = null;
//gets the ConstructorInfo for the constructor of type T with a single parameter of type IDataReader
var facadetype = GetFacadeType(type.Name);
MethodInfo loadMethod;
var linkedEntitiesInterface = facadetype.GetInterface(typeof(IFacadeLoadLinkedEntities).Name);
var lamdaParameterExpressions = new List() { paramId };
if (linkedEntitiesInterface != null)
{
loadMethod = facadetype.GetMethod("LoadById");
paramOptions = Expression.Parameter(linkedEntitiesInterface.GetGenericTypeDefinition().GenericTypeArguments[1], "options");
lamdaParameterExpressions.Add(paramOptions);
}
else
{
paramOptions = Expression.Parameter(typeof(byte?));
loadMethod = facadetype.GetMethod("LoadByID", new Type[1]{typeof(long)});
}
var facadeConstructor = facadetype.GetConstructor(new Type[0]);
var newFacade = Expression.New(facadeConstructor);
var callLoad = Expression.Call(newFacade, loadMethod, lamdaParameterExpressions);
lamdaParameterExpressions.Add(paramOptions);
var returnValue = Expression.Parameter(typeof(object));
lamdaParameterExpressions.Add(returnValue);
var entityVariable = Expression.Variable(typeof(object), "entity");
Expression.Assign(entityVariable, callLoad);
var lambda = Expression.Lambda>(
entityVariable, lamdaParameterExpressions.ToArray());
//compiles the Expression to a usable delegete.
return lambda.Compile();
}
In the mean time, I found the way to make it work:
private static Func GetDataExtractorForTypeWithId(Type type)
{
var paramId = Expression.Parameter(typeof(long), "id");
ParameterExpression paramOptions = null;
var facadetype = GetFacadeType(type.Name) ?? typeof(AzzFacade).MakeGenericType(type);
MethodInfo loadMethod;
var linkedEntitiesInterface = facadetype.GetInterface(typeof(IFacadeLoadLinkedEntities).Name);
if (linkedEntitiesInterface != null)
{
loadMethod = facadetype.GetMethod("LoadById");
paramOptions = Expression.Parameter(typeof(byte), "options");
}
else
{
paramOptions = Expression.Parameter(typeof(byte));
loadMethod = facadetype.GetMethod("LoadByID", new Type[1]{typeof(long)});
}
var facadeConstructor = facadetype.GetConstructor(new Type[0]);
if(facadeConstructor==null)
throw new NullReferenceException($"No parameterless constructor found for facade for type {type.Name}");
MethodCallExpression callLoad;
var newFacade = Expression.New(facadeConstructor);
if (linkedEntitiesInterface != null)
{
var conversionExpression = Expression.Convert(paramOptions, linkedEntitiesInterface.GetGenericArguments()[1]);
// ReSharper disable once AssignNullToNotNullAttribute
callLoad = Expression.Call(newFacade, loadMethod, paramId, conversionExpression);
}
else
{
// ReSharper disable once AssignNullToNotNullAttribute
callLoad = Expression.Call(newFacade, loadMethod, paramId);
}
var lambda = Expression.Lambda>(
// ReSharper disable once AssignNullToNotNullAttribute
callLoad, paramId, paramOptions);
//compiles the Expression to a usable delegate.
return lambda.Compile();
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.