Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/315.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/1/typo3/2.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# 如何为.Where(x=>;x.<;deep property>;.Select(y=>;y.id).Intersect(List<;int>;).Any()创建表达式树_C#_Select_Intersect_Any - Fatal编程技术网

C# 如何为.Where(x=>;x.<;deep property>;.Select(y=>;y.id).Intersect(List<;int>;).Any()创建表达式树

C# 如何为.Where(x=>;x.<;deep property>;.Select(y=>;y.id).Intersect(List<;int>;).Any()创建表达式树,c#,select,intersect,any,C#,Select,Intersect,Any,我正在创建一个方法,该方法接收一个Queryable源,一个带有属性名/路径的字符串(可以是一个深层属性,例如“TrParent.DataTypes”,以实现此x=>x.TrParent.DataTypes)和Enumerable,其中包含我需要相交的值 基本上,我需要动态创建以下查询(我的意思是和TrParent.DataTypes只在运行时知道,在示例中DT_Det_Tr不是一种类型,而是一个类): var\u vals=new List(); var res=dbContext.Set()

我正在创建一个方法,该方法接收一个
Queryable
源,一个带有属性名/路径的字符串(可以是一个深层属性,例如
“TrParent.DataTypes”
,以实现此
x=>x.TrParent.DataTypes
)和
Enumerable
,其中包含我需要相交的值

基本上,我需要动态创建以下查询(我的意思是
TrParent.DataTypes
只在运行时知道,在示例中
DT_Det_Tr
不是一种类型,而是一个类):

var\u vals=new List();
var res=dbContext.Set()
哪里
(x=>x.TrParent.DataTypes
.选择(t=>t.Id)
.相交(_vals)
.Any()
);
请记住,前面的查询只是我需要动态实现的一个示例,我真正需要的是一个表达式树,它创建一个类似于上面所示的谓词,但使用动态类型并在字符串中指定深度导航属性

因此,我使用这个函数为deep属性创建表达式:

private static LambdaExpression CreateDelegateExpression<T>(out Type resultingtype, string property, string parameterName = "x")
{
    var type = typeof(T);
    ParameterExpression param = Expression.Parameter(type, parameterName);
    Expression expr = param;
    foreach (string prop in property.Split('.'))
    {
        PropertyInfo pi = type.GetProperty(prop);
        expr = Expression.Property(expr, pi);
        type = pi.PropertyType;
    }
    Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
    LambdaExpression lambda = Expression.Lambda(delegateType, expr, param);
    resultingtype = type;
    return lambda;
}
私有静态LambdaExpression CreateDelegateExpression(输出类型resultingtype,字符串属性,字符串参数name=“x”) { var类型=类型(T); ParameterExpression param=Expression.Parameter(类型,参数名称); 表达式expr=param; foreach(property.Split('.')中的字符串属性) { PropertyInfo pi=type.GetProperty(prop); expr=Expression.Property(expr,pi); type=pi.PropertyType; } Type delegateType=typeof(Func)。MakeGenericType(typeof(T),Type); LambdaExpression lambda=Expression.lambda(delegateType,expr,param); 结果类型=类型; 返回lambda; } 到目前为止,我的职能是:

public static IQueryable<T> Intersect<T>(this IQueryable<T> source, string property, IEnumerable<int> value)
{
    //List of ids
    var _value = Expression.Constant(value);

    //Get delegate expression to the deep property and it's inner type
    Type type = null;
    var lambda = CreateDelegateExpression<T>(out type, property, "x");
    var enumtype = type.GetGenericArguments()[0];

    ParameterExpression tpe = Expression.Parameter(enumtype, "y");

    Expression propExp = Expression.Property(tpe, enumtype.GetProperty("Id"));

    MethodInfo innermethod = typeof(Queryable).GetMethods().Where(x => x.Name == "Select").First();
    //Error on next line...
    var selectCall = Expression.Call(typeof(Queryable),
                         "Select",
                         new Type[] { enumtype, typeof(long) },
                         lambda,
                         propExp);
    //TODO: Add rest of logic and actually filter the source
    return source;
}
公共静态IQueryable Intersect(此IQueryable源、字符串属性、IEnumerable值)
{
//ID列表
var _值=表达式常数(值);
//获取deep属性及其内部类型的委托表达式
Type=null;
var lambda=CreateDelegateExpression(输出类型,属性,“x”);
var enumtype=type.GetGenericArguments()[0];
ParameterExpression tpe=表达式.参数(枚举类型,“y”);
Expression propExp=Expression.Property(tpe,enumtype.GetProperty(“Id”);
MethodInfo innermethod=typeof(Queryable).GetMethods()。其中(x=>x.Name==“选择”).First();
//下一行出错。。。
var selectCall=Expression.Call(typeof(Queryable),
“选择”,
新类型[]{enumtype,typeof(long)},
兰姆达,
(xp),;
//TODO:添加其余逻辑并实际过滤源
返回源;
}
var selectCall=
行中,我得到了一个错误:

类型“System.Linq.Queryable”上的泛型方法“Select”与提供的类型参数和参数不兼容。如果方法是非泛型的,则不应提供类型参数


我在SO和其他网站上读了很多文章,但我无法通过这一部分,我觉得当我进入
.Intersect(List)部分时,我会遇到更多的麻烦。Any()
部分,因此关于这一部分的任何帮助都将是巨大的,谢谢。

如果您可以从c#4.0访问dynamic关键字,您可能能够解决以下问题:

var _vals = new List<int>();
var res = dbContext.Set<DT_Det_Tr>()
            .Where(obj => { dynamic x = obj;
               return x.TrParent.DataTypes
                .Select(t => t.Id)
                    .Intersect(_vals)
                        .Any();
                 }
            );
var\u vals=new List();
var res=dbContext.Set()
其中(obj=>{dynamic x=obj;
返回x.TrParent.DataTypes
.选择(t=>t.Id)
.相交(_vals)
.Any();
}
);

但我对你想解决的问题的细节了解不够,所以不能肯定

经过深思熟虑、调查和尝试,我想出了一个解决办法

首先,我制作了一个更简单的目标查询(我在问题中使用的静态示例),因此没有:

var res = dbContext.Set<DT_Det_Tr>()
                .Where
                (x => x.TrParent.DataTypes
                    .Select(t => t.Id)
                        .Intersect(_vals)
                            .Any()
                );
var res=dbContext.Set()
哪里
(x=>x.TrParent.DataTypes
.选择(t=>t.Id)
.相交(_vals)
.Any()
);
我做了这个:

var res = dbContext.Set<DT_Det_Tr>()
 .Where
 (x => x.TrParent.DataTypes
         .Any(y => _vals.Contains(y.Id))
 );
public static IQueryable<T> Intersect<T>(this IQueryable<T> source, string property, IEnumerable<int> value)
        {
            var type = typeof(T);
            var _value = Expression.Constant(value); //List of ids
            //Declare parameter for outer lambda
            ParameterExpression param = Expression.Parameter(type, "x");

            //Outer Lambda
            Expression expr = param;
            foreach (string prop in property.Split('.')) //Dig for deep property
            {
                PropertyInfo pi = type.GetProperty(prop);
                expr = Expression.Property(expr, pi);
                type = pi.PropertyType;
            }

            //Get deep property's type
            var enumtype = type.GetGenericArguments()[0];
            //Declare parameter for inner lambda
            ParameterExpression tpe = Expression.Parameter(enumtype, "y");

            //Inner Collection lambda logic
            //Property for inner lambda
            Expression propExp = Expression.Property(tpe, enumtype.GetProperty("Id"));
            //Contains method call .Contains(y.Id)
            var containsMethodExp = Expression.Call(typeof(Enumerable), "Contains", new[] { propExp.Type }, _value, propExp);
            //Create Expression<Func<enumtype, bool>>
            var innerDelegateType = typeof(Func<,>).MakeGenericType(enumtype, typeof(bool));
            //Create Inner lambda y => _vals.Contains(y.Id)
            var innerFunction = Expression.Lambda(innerDelegateType, containsMethodExp, tpe);
            //Get Any method info
            var anyMethod = typeof(Enumerable).GetMethods().Where(m => m.Name == "Any" && m.GetParameters().Length == 2).Single().MakeGenericMethod(enumtype);
            //Call Any with inner function .Any(y => _vals.Contains(y.Id))
            var outerFunction = Expression.Call(anyMethod, expr, innerFunction);
            //Call Where
            MethodCallExpression whereCallExpression = Expression.Call
            (
                typeof(Queryable),
                "Where",
                new Type[] { source.ElementType },
                source.Expression,
                Expression.Lambda<Func<T, bool>>(outerFunction, new ParameterExpression[] { param })
            );
            //Create and return query
            return source.Provider.CreateQuery<T>(whereCallExpression);
        }
var res=dbContext.Set()
哪里
(x=>x.TrParent.DataTypes
.Any(y=>_vals.Contains(y.Id))
);
这更容易翻译成表达式(至少对我来说是这样),因为它省略了Select调用

我放弃了创建深度导航属性表达式的方法,并在我的Intersect函数中对其进行了精简,这是因为它正在做一些我在这里并不真正需要的工作,加上我需要访问其中使用的一些变量,然后我做了以下操作:

var res = dbContext.Set<DT_Det_Tr>()
 .Where
 (x => x.TrParent.DataTypes
         .Any(y => _vals.Contains(y.Id))
 );
public static IQueryable<T> Intersect<T>(this IQueryable<T> source, string property, IEnumerable<int> value)
        {
            var type = typeof(T);
            var _value = Expression.Constant(value); //List of ids
            //Declare parameter for outer lambda
            ParameterExpression param = Expression.Parameter(type, "x");

            //Outer Lambda
            Expression expr = param;
            foreach (string prop in property.Split('.')) //Dig for deep property
            {
                PropertyInfo pi = type.GetProperty(prop);
                expr = Expression.Property(expr, pi);
                type = pi.PropertyType;
            }

            //Get deep property's type
            var enumtype = type.GetGenericArguments()[0];
            //Declare parameter for inner lambda
            ParameterExpression tpe = Expression.Parameter(enumtype, "y");

            //Inner Collection lambda logic
            //Property for inner lambda
            Expression propExp = Expression.Property(tpe, enumtype.GetProperty("Id"));
            //Contains method call .Contains(y.Id)
            var containsMethodExp = Expression.Call(typeof(Enumerable), "Contains", new[] { propExp.Type }, _value, propExp);
            //Create Expression<Func<enumtype, bool>>
            var innerDelegateType = typeof(Func<,>).MakeGenericType(enumtype, typeof(bool));
            //Create Inner lambda y => _vals.Contains(y.Id)
            var innerFunction = Expression.Lambda(innerDelegateType, containsMethodExp, tpe);
            //Get Any method info
            var anyMethod = typeof(Enumerable).GetMethods().Where(m => m.Name == "Any" && m.GetParameters().Length == 2).Single().MakeGenericMethod(enumtype);
            //Call Any with inner function .Any(y => _vals.Contains(y.Id))
            var outerFunction = Expression.Call(anyMethod, expr, innerFunction);
            //Call Where
            MethodCallExpression whereCallExpression = Expression.Call
            (
                typeof(Queryable),
                "Where",
                new Type[] { source.ElementType },
                source.Expression,
                Expression.Lambda<Func<T, bool>>(outerFunction, new ParameterExpression[] { param })
            );
            //Create and return query
            return source.Provider.CreateQuery<T>(whereCallExpression);
        }
公共静态IQueryable Intersect(此IQueryable源、字符串属性、IEnumerable值)
{
var类型=类型(T);
var _value=Expression.Constant(value);//ID列表
//为外部lambda声明参数
ParameterExpression param=表达式参数(类型为“x”);
//外Lambda
表达式expr=param;
foreach(property.Split('.')中的字符串prop//Dig for deep属性
{
PropertyInfo pi=type.GetProperty(prop);
expr=Expression.Property(expr,pi);
type=pi.PropertyType;
}
//获取深度属性的类型
var enumtype=type.GetGenericArguments()[0];
//为内部lambda声明参数
ParameterExpression tpe=表达式.参数(枚举类型,“y”);
//内收集lambda逻辑
//内lambda的性质
Expression propExp=Expression.Property(tpe