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

时间:2017-03-02 15:34:24

标签: c# linq lambda

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

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

我正在使用的代码基于MainList创建一个列表。然后我通过传递SearchObject类型和我想要填充的参数来创建select表达式。它一直运行到倒数第二行。

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

我得到的错误是:

附加信息:类型&#39; WebApplication.SearchObject&#39;的ParameterExpression不能用于类型&#39; WebApplication.MainList&#39;

的委托参数

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

2 个答案:

答案 0 :(得分:4)

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

第二个问题是Expression.Bind的使用。由于源和目标是不同的类型,因此您不能使用同一个PropertyInfo。第一个参数必须是目标类型PropertyInfo的{​​{1}},而第二个 - 表达式来自源类型T(在您的情况下,MainList上的参数为指定的属性名称。)。

正确的实现是这样的:

Expression.Property

答案 1 :(得分:1)

异常 ParameterExpression of type 'WebApplication.SearchObject' cannot be used for delegate parameter of type 'WebApplication.MainList' 解释:

含义:ParameterExpression类型 typeof(T) 与Expression.Lambda Func<MainList, T> - &gt;之间存在不匹配 MainList

您:

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

应该是:

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