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# 试图将父属性用作子集合表达式中的参数;林奇抛出;无法将MethodCallExpressionN强制转换为LambdaExpression“;_C#_Linq_Expression_Linq Expressions_Linqkit - Fatal编程技术网

C# 试图将父属性用作子集合表达式中的参数;林奇抛出;无法将MethodCallExpressionN强制转换为LambdaExpression“;

C# 试图将父属性用作子集合表达式中的参数;林奇抛出;无法将MethodCallExpressionN强制转换为LambdaExpression“;,c#,linq,expression,linq-expressions,linqkit,C#,Linq,Expression,Linq Expressions,Linqkit,我试图动态构造一个类似于下面的表达式,在这里我可以使用相同的比较函数,但是可以传入被比较的值,因为该值是从查询中的“更高”属性传递的 var people=people .其中(p=>p.汽车 。任何(c=>c.颜色==p.FavoriteColour)); 我相信我已经正确地构造了查询,但是ExpressionExpander.VisitMethodCall(..)方法在我尝试使用它时抛出以下异常: “无法将'System.Linq.Expressions.InstanceMethodCal

我试图动态构造一个类似于下面的表达式,在这里我可以使用相同的比较函数,但是可以传入被比较的值,因为该值是从查询中的“更高”属性传递的

var people=people
.其中(p=>p.汽车
。任何(c=>c.颜色==p.FavoriteColour));
我相信我已经正确地构造了查询,但是
ExpressionExpander.VisitMethodCall(..)
方法在我尝试使用它时抛出以下异常:

“无法将'System.Linq.Expressions.InstanceMethodCallExpressionN'类型的对象强制转换为'System.Linq.Expressions.LambdaExpression'类型”

在实际代码中,使用实体框架和实际的
IQueryable
,我经常得到:

“无法将'System.Linq.Expressions.MethodCallExpressionN'类型的对象强制转换为'System.Linq.Expressions.LambdaExpression'”类型。”

我已经为我的问题构建了一个LinqPad友好的示例,尽可能简单

void Main()
{
var tuples=新列表(){
新元组(“Hello”,4),
新元组(“世界”,2),
新元组(“奶酪”,20)
};
var queryableTuples=tuples.AsQueryable();
//对于本例,我想检查这些字符串中的哪些字符串比其附带的数字长。
//我要构建的表达式需要使用项的一个值(int)来构建表达式。
//基本上,我只想构建这个:
//.其中(x=>x.Item1.Length>x.Item2)
var expressionToCheckTuple=BuildExpressionToCheckTuple();
var result=queryableTuples
.AsExpandable()
.Where(t=>expressionToCheckTuple.Invoke(t))
.ToList();
}
公共表达式BuildExpressionToCheckStringLength(int minLength){
返回str=>str.Length>minLength;
}
公共表达式BuildExpressionToCheckTuple(){
//我收到了包含以下内容的内容(如元组):
//*构造表达式所需的值(例如“最小长度”)
//*调用表达式所需的值(例如字符串)
return tuple=>BuildExpressionToCheckStringLength(tuple.Item2/*长度*/).Invoke(tuple.Item1/*字符串*/);
}
如果我做了一些明显错误的事情,我真的很感激你朝着正确的方向轻推我!谢谢


编辑:我知道以下方法可行:

Expression<Func<Tuple<string, int>, bool>> expr = x => x.Item1.Length > x.Item2;

var result = queryableTuples
    .AsExpandable()
    .Where (t => expr.Invoke(t))
    .ToList();
表达式expr=x=>x.Item1.Length>x.Item2;
var result=queryableTuples
.AsExpandable()
.Where(t=>expr.Invoke(t))
.ToList();
但是,我试图将比较与参数的位置分开,因为比较可能很复杂,我希望将其重新用于许多不同的查询(两个参数的位置各不相同)。还打算通过另一个表达式实际计算其中一个参数(在示例中为“最小长度”)


编辑:很抱歉,我刚刚意识到,当尝试针对我的示例代码时,一些答案会起作用,因为我的示例只是伪装成一个
IQueryable
,但下面仍然是一个
列表。我之所以使用LinqKit,首先是因为EntityFramework DbContext中的实际
IQueryable
将调用Linq to SQL,因此必须能够被Linq解析为SQL本身。LinqKit通过将所有内容扩展到表达式来实现这一点


解决方案多亏了,我想我已经意识到我错在哪里了

如果某个值来自查询中的某个位置(即不是一个已知的值),则必须将其引用/表达式/变量构建到表达式中

在我最初的示例中,我试图传递从表达式中获取的“minLength”值,并将其传递给一个方法。该方法调用不能提前完成,因为它使用了表达式中的值,也不能在表达式中完成,因为无法在表达式中构建表达式

那么,如何避免这种情况呢?我选择编写表达式,以便可以使用其他参数调用它们。虽然这样做的缺点是参数不再“命名”,我可能会得到一个
表达式
或其他类似的东西

//新签名。
公共表达式BuildExpressionToCheckStringLength(){
//现在需要两个参数。
返回(str,minLength)=>str.Length>minLength;
}
公共表达式BuildExpressionToCheckTuple(){
//在手之前构造表达式。
var expression=BuildExpressionToCheckStringLength();
//使用这两个值调用表达式。
return tuple=>expression.Invoke(tuple.Item1/*string*/,tuple.Item2/*长度*/);
}

因此,您正在寻找类似以下内容:

public static class Program
    {
        public class Person
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
        }

        public static IQueryable<T> WherePropertyEquals<T, TProperty>(
            this IQueryable<T> src, Expression<Func<T, TProperty>> property, TProperty value)
        {
            var result = src.Where(e => property.Invoke(e).Equals(value));
            return result;
        }

        public static IQueryable<T> WhereGreater<T, TProperty>(
            this IQueryable<T> src, Expression<Func<T, TProperty>> property, TProperty value)
            where TProperty : IComparable<TProperty>
        {
            var result = src.Where(e => property.Invoke(e).CompareTo(value) > 0);
            return result;
        }

        public static IQueryable<T> WhereGreater<T, TProperty>(
            this IQueryable<T> src, Expression<Func<T, TProperty>> left, Expression<Func<T, TProperty>> right)
            where TProperty : IComparable<TProperty>
        {
            var result = src.Where(e => left.Invoke(e).CompareTo(right.Invoke(e)) > 0);
            return result;
        }

        public static void Main()
        {
            var persons = new List<Person>()
                {
                    new Person
                        {
                            FirstName = "Jhon",
                            LastName = "Smith"
                        },
                    new Person
                        {
                            FirstName = "Chuck",
                            LastName = "Norris"
                        },
                    new Person
                        {
                            FirstName = "Ben",
                            LastName = "Jenkinson"
                        },
                    new Person
                        {
                            FirstName = "Barack",
                            LastName = "Obama"
                        }
                }
                .AsQueryable()
                .AsExpandable();

            var chuck = persons.WherePropertyEquals(p => p.FirstName, "Chuck").First();
            var ben = persons.WhereGreater(p => p.LastName.Length, 6).First();
            var barack = persons.WhereGreater(p => p.FirstName.Length, p => p.LastName.Length).First();
        }
公共静态类程序
{
公共阶层人士
{
公共字符串名{get;set;}
公共字符串LastName{get;set;}
}
公共静态可查询属性相等的位置(
此IQueryable src、表达式属性、TProperty值)
{
var result=src.Where(e=>property.Invoke(e).Equals(value));
返回结果;
}
公共静态IQueryable(可在更大的地方使用)(
此IQueryable src、表达式属性、TProperty值)
其中t属性:i可比较
{
var result=src.Where(e=>property.Invoke(e).CompareTo(value)>0);
返回结果;
}
公共静态IQueryable(可在更大的地方使用)(
此IQueryable src,表达式左,表达式右)
其中t属性:i可比较
{
var result=src.Where(e=>left.Invoke(e).CompareTo(right.Invo
public Expression<Func<int, Func<string, bool>>> ExpressionToCheckStringLengthBuilder() {
    return minLength =>
        str => str.Length > minLength;
}

public Expression<Func<Tuple<string, int>, bool>> BuildExpressionToCheckTuple() {
    // I'm passed something (eg. Tuple) that contains:
    //  * a value that I need to construct the expression (eg. the 'min length')
    //  * the value that I will need to invoke the expression (eg. the string)

    // Putting builder into a variable so that the resulting expression will be 
    // visible to tools that analyze the expression.
    var builder = ExpressionToCheckStringLengthBuilder();

    return tuple => builder.Invoke(tuple.Item2 /* the length */).Invoke(tuple.Item1 /* string */);
}