C# LINQ表达式的运行时创建
假设我有这样的表达:C# LINQ表达式的运行时创建,c#,linq,lambda,linq-to-objects,mongodb-.net-driver,C#,Linq,Lambda,Linq To Objects,Mongodb .net Driver,假设我有这样的表达: int setsize = 20; Expression<Func<Foo, bool>> predicate = x => x.Seed % setsize == 1 || x.Seed % setsize == 4; 基本上,我希望在运行时动态构建表达式,使其完全复制编译器为“硬编码”版本生成的内容 任何帮助都将不胜感激 编辑 (和),下面是我的一次尝试。
int setsize = 20;
Expression<Func<Foo, bool>> predicate = x => x.Seed % setsize == 1
|| x.Seed % setsize == 4;
基本上,我希望在运行时动态构建表达式,使其完全复制编译器为“硬编码”版本生成的内容
任何帮助都将不胜感激
编辑
(和),下面是我的一次尝试。我把它贴在问题中,以供将来参考。帕斯宾应该把它取下来还是停止他们的服务,或者
using MongoRepository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
class Program
{
static void Main(string[] args)
{
MongoRepository<Foo> repo = new MongoRepository<Foo>();
var reporesult = repo.All().Where(IsInSet(new[] { 1, 4 }, 20)).ToArray();
}
private static Expression<Func<Foo, bool>> IsInSet(IEnumerable<int> seeds, int setsize)
{
if (seeds == null)
throw new ArgumentNullException("s");
if (!seeds.Any())
throw new ArgumentException("No sets specified");
return seeds.Select<int, Expression<Func<Foo, bool>>>(seed => x => x.Seed % setsize == seed).JoinByOr();
}
}
public class Foo : Entity
{
public int Seed { get; set; }
}
public static class Extensions
{
public static Expression<Func<T, bool>> JoinByOr<T>(this IEnumerable<Expression<Func<T, bool>>> filters)
{
var firstFilter = filters.First();
var body = firstFilter.Body;
var param = firstFilter.Parameters.ToArray();
foreach (var nextFilter in filters.Skip(1))
{
var nextBody = Expression.Invoke(nextFilter, param);
body = Expression.Or(body, nextBody);
}
return Expression.Lambda<Func<T, bool>>(body, param);
}
}
使用MongoRepository;
使用制度;
使用System.Collections.Generic;
使用System.Linq;
使用System.Linq.Expressions;
班级计划
{
静态void Main(字符串[]参数)
{
MongoRepository回购=新MongoRepository();
var reposult=repo.All().Where(IsInSet(new[]{1,4},20)).ToArray();
}
私有静态表达式IsInSet(IEnumerable seeds,int setsize)
{
if(seeds==null)
抛出新的ArgumentNullException(“s”);
如果(!seeds.Any())
抛出新ArgumentException(“未指定集合”);
返回seed.Select(seed=>x=>x.seed%setsize==seed).JoinByOr();
}
}
公共类Foo:Entity
{
公共整数种子{get;set;}
}
公共静态类扩展
{
公共静态表达式JoinByOr(此IEnumerable筛选器)
{
var firstFilter=filters.First();
var body=firstFilter.body;
var param=firstFilter.Parameters.ToArray();
foreach(过滤器中的var nextFilter.Skip(1))
{
var nextBody=Expression.Invoke(nextFilter,param);
body=表达式。或(body,nextBody);
}
返回表达式.Lambda(body,param);
}
}
这将导致:不支持where子句:
请尝试以下操作:
public Expression<Func<Foo, bool>> GetExpression<T>(
int setSize, int[] elements,
Expression<Func<Foo, T>> property)
{
var seedProperty = GetPropertyInfo(property);
var parameter = Expression.Parameter(typeof(Foo));
Expression body = null;
foreach(var element in elements)
{
var condition = GetCondition(parameter, seedProperty, setSize, element);
if(body == null)
body = condition;
else
body = Expression.OrElse(body, condition);
}
if(body == null)
body = Expression.Constant(false);
return Expression.Lambda<Func<Foo, bool>>(body, parameter);
}
public Expression GetCondition(
ParameterExpression parameter, PropertyInfo seedProperty,
int setSize, int element)
{
return Expression.Equal(
Expression.Modulo(Expression.Property(parameter, seedProperty),
Expression.Constant(setSize)),
Expression.Constant(element));
}
public static PropertyInfo GetPropertyInfo(LambdaExpression propertyExpression)
{
if (propertyExpression == null)
throw new ArgumentNullException("propertyExpression");
var body = propertyExpression.Body as MemberExpression;
if (body == null)
{
throw new ArgumentException(
string.Format(
"'propertyExpression' should be a member expression, "
+ "but it is a {0}", propertyExpression.Body.GetType()));
}
var propertyInfo = body.Member as PropertyInfo;
if (propertyInfo == null)
{
throw new ArgumentException(
string.Format(
"The member used in the expression should be a property, "
+ "but it is a {0}", body.Member.GetType()));
}
return propertyInfo;
}
如果您希望它在
Foo
中也是通用的,您需要这样更改它:
GetExpression(setSize, elements, x => x.Seed);
public static Expression<Func<TEntity, bool>> GetExpression<TEntity, TProperty>(
int setSize, int[] elements,
Expression<Func<TEntity, TProperty>> property)
{
var propertyInfo = GetPropertyInfo(property);
var parameter = Expression.Parameter(typeof(TEntity));
Expression body = null;
foreach(var element in elements)
{
var condition = GetCondition(parameter, propertyInfo , setSize, element);
if(body == null)
body = condition;
else
body = Expression.OrElse(body, condition);
}
if(body == null)
body = Expression.Constant(false);
return Expression.Lambda<Func<TEntity, bool>>(body, parameter);
}
GetExpression(setSize, elements, (Foo x) => x.Seed);
在这种情况下,显式指定
x
的类型很重要,否则类型推断将不起作用,您必须将Foo
和属性的类型都指定为GetExpression
的泛型参数。请显示您的一些尝试,或至少一次尝试。给您:。这将导致:不支持where子句:
。真糟糕!真管用!谢谢现在,我不想成为一个蠢货什么的,有没有什么方法可以避免使用“Seed”
字符串,这样在重构等过程中也会用到这个?更具体地说:我不能“只是”传递一个“lamba”或其他东西来让它更“通用”一点吗?无论哪种方式:这个答案是非常感谢!先生,你真是一场史诗般的胜利!谢谢!
GetExpression(setSize, elements, x => x.Seed);
public static Expression<Func<TEntity, bool>> GetExpression<TEntity, TProperty>(
int setSize, int[] elements,
Expression<Func<TEntity, TProperty>> property)
{
var propertyInfo = GetPropertyInfo(property);
var parameter = Expression.Parameter(typeof(TEntity));
Expression body = null;
foreach(var element in elements)
{
var condition = GetCondition(parameter, propertyInfo , setSize, element);
if(body == null)
body = condition;
else
body = Expression.OrElse(body, condition);
}
if(body == null)
body = Expression.Constant(false);
return Expression.Lambda<Func<TEntity, bool>>(body, parameter);
}
GetExpression(setSize, elements, (Foo x) => x.Seed);