Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# LINQ表达式的运行时创建_C#_Linq_Lambda_Linq To Objects_Mongodb .net Driver - Fatal编程技术网

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