表达式树可枚举 Select
Enumerable Select by Expression Tree
我正在学习 "Expression Tree" 但我无法执行这些表达式:
// first case
someList.Select(p => p.SomeProperty);
和
// second case
someList.Select(p => new OtherClass
{
SomeProperty = p.SomeProperty
})
对于 "first case" 我试过这样做:
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:类型 'System.Linq.Enumerable' 上的泛型方法 'Select' 与提供的类型参数和参数不兼容。如果方法是非泛型的,则不应提供类型参数。
关于"second case",我不知道如何进行。
有人可以指导我吗?
您可以做什么的一些示例:
给定
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);
你不应该曾经在单元测试和"experimentation"程序中使用AsQueryable()
但(像这样一)。为了让@Peter 开心,我将添加另一个可能的条件:如果你 really 知道它的作用(而不是 think 你知道它的作用,真的!),那你就可以用了。但是如果是第一次使用,我还是建议你在SO上问问你用的对不对。
IQueryable<SomeClass> queryable = someList.AsQueryable();
直接使用Queryable.Select()
IQueryable<string> q2 = queryable.Select(lambda);
构建一个 Select
并在查询中使用 CreateQuery
(这与 Queryable.Select
内部所做的非常相似)"inject"。
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);
冷静下来,经过一番研究,我发现我的代码中缺少什么...
关于第一个案例:
Expression.Call(
typeof(Enumerable),
"Select",
new Type[]
{
typeof(SomeClass),
typeof(string)
},
Expression.Constant(someList), // <---------------- HERE IT IS
Expression.Lambda(
someProperty,
someParam
)
);
对于第二种情况,我通过下面的代码创建了"new"表达式:
var bind = Expression.Bind(typeof(OtherClass).GetProperty("SomeProperty"), someProperty);
var otherClassNew = Expression.New(typeof(OtherClass));
var otherClassInit = Expression.MemberInit(otherClassNew, bind);
总之,谢谢大家的帮助!
我正在学习 "Expression Tree" 但我无法执行这些表达式:
// first case
someList.Select(p => p.SomeProperty);
和
// second case
someList.Select(p => new OtherClass
{
SomeProperty = p.SomeProperty
})
对于 "first case" 我试过这样做:
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:类型 'System.Linq.Enumerable' 上的泛型方法 'Select' 与提供的类型参数和参数不兼容。如果方法是非泛型的,则不应提供类型参数。
关于"second case",我不知道如何进行。
有人可以指导我吗?
您可以做什么的一些示例:
给定
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);
你不应该曾经在单元测试和"experimentation"程序中使用AsQueryable()
但(像这样一)。为了让@Peter 开心,我将添加另一个可能的条件:如果你 really 知道它的作用(而不是 think 你知道它的作用,真的!),那你就可以用了。但是如果是第一次使用,我还是建议你在SO上问问你用的对不对。
IQueryable<SomeClass> queryable = someList.AsQueryable();
直接使用Queryable.Select()
IQueryable<string> q2 = queryable.Select(lambda);
构建一个 Select
并在查询中使用 CreateQuery
(这与 Queryable.Select
内部所做的非常相似)"inject"。
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);
冷静下来,经过一番研究,我发现我的代码中缺少什么...
关于第一个案例:
Expression.Call(
typeof(Enumerable),
"Select",
new Type[]
{
typeof(SomeClass),
typeof(string)
},
Expression.Constant(someList), // <---------------- HERE IT IS
Expression.Lambda(
someProperty,
someParam
)
);
对于第二种情况,我通过下面的代码创建了"new"表达式:
var bind = Expression.Bind(typeof(OtherClass).GetProperty("SomeProperty"), someProperty);
var otherClassNew = Expression.New(typeof(OtherClass));
var otherClassInit = Expression.MemberInit(otherClassNew, bind);
总之,谢谢大家的帮助!