使用表达式构建器进行选择的动态lambda



我正在尝试编写动态选择语句。我有以下内容:

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; }
}

我想像以下

那样构建表达式
var newList = MainList.Select(n => new SearchObject { Prop1 = n.Prop1});

我正在使用的代码创建基于主列表的列表。然后,我通过传递搜索对象类型和我要填充的参数来创建选择表达式。它运行到第二行。

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();
}

我遇到的错误是:

附加信息:类型'webapplication.searchobject'的参数不能用于类型的委托参数'webapplication.mainlist'

我不确定错误的含义以及如何解决问题。

第一个问题是,正如Jeroen van Langen已经提到的那样,参数的类型必须为MainList

第二个问题是Expression.Bind的使用情况。由于源和目标是不同的类型,因此您不能使用一个和相同的PropertyInfo。第一个参数必须是目标类型TPropertyInfo,而第二个则来自源类型MainList(在您的情况下,带有指定属性名称的参数上的Expression.Property)。

正确的实现就是这样:

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();
}

例外 ParameterExpression of type 'WebApplication.SearchObject' cannot be used for delegate parameter of type 'WebApplication.MainList' 解释了:

含义: ParameterExpression类型 typeof(T) 与expession.lambda Func<MainList, T>-> MainList

之间存在不匹配。

您:

var par = Expression.Parameter(typeof(T), "n");

应该是:

var par = Expression.Parameter(typeof(MainList), "n");

最新更新