Dynamic lambda using an expression builder for select
I am trying to write a dynamic select statement. I have the following:
public class MainList
{
public string Prop1{ get; set; }
public string Prop2{ get; set; }
public string Prop3{ get; set; }
}
public class SearchObject
{
public string Prop1{ get; set; }
}
I want build the expression like the following
var newList = MainList.Select(n => new SearchObject { Prop1 = n.Prop1});
The code I am using creates a list based on MainList. I then create the select expression by passing the SearchObject type and the parameters I want to populate, for now. It runs until the second to last line.
public void Start()
{
List<MainList> newList = new List<MainList>(); //This has a ton list objects
var result = newList.Select(CreateSelect<SearchObject>("Prop1"));
}
public static Func<MainList, T> CreateSelect<T>(string fields)
{
var par = Expression.Parameter(typeof(T), "n");
var newInstance= Expression.New(typeof(T));
var bindings = fields.Split(',').Select(o => o.Trim())
.Select(n => {
var p = typeof(T).GetProperty(n);
var original = Expression.Property(par, p);
return Expression.Bind(p, original);
}
);
var newT= Expression.MemberInit(newInstance, bindings);
var lambda = Expression.Lambda<Func<MainList, T>>(newT, par); //ERROR HAPPENS HERE
return lambda.Compile();
}
The error I get is:
Additional information: ParameterExpression of type 'WebApplication.SearchObject' cannot be used for delegate parameter of type 'WebApplication.MainList'
I am unsure on the meaning of the error and also how to resolve the issue.
The first issue is, as already mentioned by Jeroen van Langen, the type of the parameter must be MainList
.
The second issue is the usage of the Expression.Bind
. Since the source and target are different types, you cannot use one and the same PropertyInfo
. The first argument must be a PropertyInfo
of the target type T
, while the second - expression coming from the source type MainList
(in your case, Expression.Property
on the parameter with the specified property name).
The correct implementation is something like this:
public static Func<MainList, T> CreateSelect<T>(string fields)
{
var parameter = Expression.Parameter(typeof(MainList), "n");
var bindings = fields.Split(',')
.Select(name => name.Trim())
.Select(name => Expression.Bind(
typeof(T).GetProperty(name),
Expression.Property(parameter, name)
));
var newT = Expression.MemberInit(Expression.New(typeof(T)), bindings);
var lambda = Expression.Lambda<Func<MainList, T>>(newT, parameter);
return lambda.Compile();
}
The exception ParameterExpression of type 'WebApplication.SearchObject' cannot be used for delegate parameter of type 'WebApplication.MainList'
explained:
Meaning: There is a mismatch between the ParameterExpression
type typeof(T)
and the Expression.Lambda Func<MainList, T>
--> MainList
Your:
var par = Expression.Parameter(typeof(T), "n");
should be:
var par = Expression.Parameter(typeof(MainList), "n");
链接地址: http://www.djcxy.com/p/68302.html