可通过表达式树

时间:2015-06-26 02:26:33

标签: c# lambda expression expression-trees enumerable

我正在学习" Expression Tree"但我没有设法执行这些表达:

// first case
someList.Select(p => p.SomeProperty);

// second case
someList.Select(p => new OtherClass 
{
    SomeProperty = p.SomeProperty
})

第一个案例"我试过这样做:

var someList = new List<SomeClass>();
someList.Add(new SomeClass { SomeProperty = "Hello" });

var someParam = Expression.Parameter(typeof(SomeClass), "p");
var someProperty = Expression.Property(someParam, "SomeProperty");

Expression.Call(
    typeof(Enumerable),
    "Select",
    new Type[]
    {
        typeof(SomeClass),
        typeof(string)
    },
    Expression.Lambda(
        someProperty,
        someParam
    )
).Dump();

但是我收到了这个错误:

InvalidOperationException:没有通用方法&#39;选择&#39; on type&#39; System.Linq.Enumerable&#39;与提供的类型参数和参数兼容。如果方法是非泛型的,则不应提供类型参数。

关于&#34;第二个案例&#34;,我没有意识到如何继续。

任何人都可以在这里指导我吗?

2 个答案:

答案 0 :(得分:1)

冷静下来,经过一些研究,我发现我的代码中缺少了什么......

关于第一案:

Expression.Call(
    typeof(Enumerable),
    "Select",
    new Type[]
    {
        typeof(SomeClass),
        typeof(string)
    },
    Expression.Constant(someList), // <---------------- HERE IT IS
    Expression.Lambda(
        someProperty,
        someParam
    )
);

对于第二种情况,我通过以下代码创建了“新”表达式:

var bind = Expression.Bind(typeof(OtherClass).GetProperty("SomeProperty"), someProperty);
var otherClassNew = Expression.New(typeof(OtherClass));
var otherClassInit = Expression.MemberInit(otherClassNew, bind);

无论如何,谢谢大家的帮助!

答案 1 :(得分:0)

您可以做的一些例子:

鉴于

public class SomeClass
{
    public string SomeProperty { get; set; }
}

var someList = new List<SomeClass>();
someList.Add(new SomeClass { SomeProperty = "Hello" });

var someParam = Expression.Parameter(typeof(SomeClass), "p");
var someProperty = Expression.Property(someParam, "SomeProperty");

Expression<Func<SomeClass, string>> lambda = Expression.Lambda<Func<SomeClass, string>>(someProperty, someParam); // p => p.SomeProperty

使用IEnumerable<SomeClass> ...请注意.Compile()

Func<SomeClass, string> compiled = lambda.Compile();
IEnumerable<string> q1 = someList.Select(compiled);

你不应该永远在单元测试中使用AsQueryable() 并且&#34;实验&#34;程序(像这样)。只是为了让@Peter高兴,我会添加另一个可能的条件:如果你真的知道它做了什么(不是想想你知道它做了什么,真的!),那么你可以使用它。但如果是第一次使用它,我仍然建议您询问是否正确使用它。

IQueryable<SomeClass> queryable = someList.AsQueryable();

直接使用Queryable.Select()

IQueryable<string> q2 = queryable.Select(lambda);

构建Select并使用CreateQuery(这与Queryable.Select内部的内容非常类似)&#34; inject&#34;它在查询中。

MethodInfo select = (from x in typeof(Queryable).GetMethods()
                    where x.Name == "Select" && x.IsGenericMethod
                    let gens = x.GetGenericArguments()
                    where gens.Length == 2
                    let pars = x.GetParameters()
                    where pars.Length == 2 && 
                        pars[0].ParameterType == typeof(IQueryable<>).MakeGenericType(gens[0]) &&
                        pars[1].ParameterType == typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(gens))
                    select x).Single().MakeGenericMethod(typeof(SomeClass), typeof(string));

MethodCallExpression select2 = Expression.Call(null, select, Expression.Constant(queryable), lambda);

IQueryProvider provider = queryable.Provider;
IQueryable<string> q3 = provider.CreateQuery<string>(select2);