Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/296.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# 无法使用列表手动创建Lambda表达式树<;T>;_C#_Linq_Generics_Expression Trees - Fatal编程技术网

C# 无法使用列表手动创建Lambda表达式树<;T>;

C# 无法使用列表手动创建Lambda表达式树<;T>;,c#,linq,generics,expression-trees,C#,Linq,Generics,Expression Trees,我需要手动创建此lambda表达式的帮助。我无法通过正确创建MemberExpression来隔离基础列表的“Breed”属性品种是本例中狗的一个属性 这是我需要手动创建的lambda: 以下是我试图获得品种属性的尝试: ParameterExpression dogParam = Expression.Parameter(typeof(List<Dog>), "dog"); MemberExpression dogMember = Expressio

我需要手动创建此lambda表达式的帮助。我无法通过正确创建
MemberExpression
来隔离基础
列表的“
Breed
”属性<代码>品种
是本例中
的一个属性

这是我需要手动创建的lambda:

以下是我试图获得
品种
属性的尝试:

ParameterExpression dogParam = Expression.Parameter(typeof(List<Dog>), "dog");

MemberExpression dogMember = 
    Expression.Field(dogParam, dogMember.Type.GetGenericTypeDefinition().GetProperty("Breed"));
ParameterExpression dogParam=Expression.Parameter(typeof(List),“dog”);
MemberExpression dogMember=
Expression.Field(dogParam,dogMember.Type.GetGenericTypeDefinition().GetProperty(“品种”);

我不确定您的问题到底出在哪里,但它已经帮助您找到您最可能需要的API:

您可以使用
Expression.Lambda
创建Lambda表达式作为
选择的参数。在lambda表达式中,您需要
expression.MakeMemberAccess
来访问
Breed
属性。您需要使用反射方法(例如
Type.GetMember
)来获取相关的
MemberInfo
对象。

这是一种痛苦,一种真正的痛苦

首先请注意,您可以作弊,然后看看编译器生成了什么:

Expression<Func<List<Dog>, int>> exp = dogList => dogList.Select(d => d.Breed.Trim().Length).OrderByDescending(d1 => d1).First();

作弊:
exp=dogList=>dogList.Select(d=>d.Breed.Trim().Length).OrderByDescending(d1=>d1)。首先()
然后查看VS调试程序“这是我需要手动创建的lambda:”下的代码不是lambda表达式。这是一个
int
表达式。这看起来非常有用。我会仔细检查它,但它看起来正是我需要的@ChiliYago如果您需要,我会为.NET5.0的所有
MethodInfo
保留一个要点(它是自动生成的,我有一个脚本来完成它):。你可以复制/粘贴你需要的(就像我在回复中所做的那样)非常感谢!
Expression<Func<List<Dog>, int>> exp = dogList => dogList.Select(d => d.Breed.Trim().Length).OrderByDescending(d1 => d1).First();
// The dogList parameter
ParameterExpression dogParam = Expression.Parameter(typeof(List<Dog>), "dog");

// Begin of inner Select expression

// d parameter
ParameterExpression dParam = Expression.Parameter(typeof(Dog), "d");

// d.Breed *property* access (if it is a *field*, use Expression.Field)
MemberExpression dogProperty = Expression.Property(dParam, nameof(Dog.Breed));

// d.Breed.Trim() method call
MethodCallExpression trimCall = Expression.Call(dogProperty, nameof(string.Trim), Type.EmptyTypes);

// d.Breed.Trim().Length property access
MemberExpression lengthProperty = Expression.Property(trimCall, nameof(string.Length));

// d => d.Breed.Trim().Length
Expression<Func<Dog, int>> selectExpression = Expression.Lambda<Func<Dog, int>>(lengthProperty, dParam);

// End of inner Select expression

// Find the "right" overload of Enumerable.Select... A pain.
MethodInfo selectTSourceTResult = (from x in typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
                                    where x.Name == nameof(Enumerable.Select)
                                    let args = x.GetGenericArguments()
                                    where args.Length == 2
                                    let pars = x.GetParameters()
                                    where pars.Length == 2 &&
                                        pars[0].ParameterType == typeof(IEnumerable<>).MakeGenericType(args[0]) &&
                                        pars[1].ParameterType == typeof(Func<,>).MakeGenericType(args[0], args[1])
                                    select x).Single();

// Make the generic overload of Enumerable.Select "specific" for using with Func<Dog, int>
MethodInfo selectDogInt32 = selectTSourceTResult.MakeGenericMethod(typeof(Dog), typeof(int));

// Note that Enumerable.Select is a static method, the first parameter is the IEnumerable, the second is the Func<,>
// Enumerable.Select(dogList, d => d.Breed.Trim().Length)
MethodCallExpression selectCall = Expression.Call(selectDogInt32, dogParam, selectExpression);

// Begin of inner OrderByDescending expression

// d1 parameter
ParameterExpression d1Param = Expression.Parameter(typeof(int), "d1");

// d1 => d1
Expression<Func<int, int>> orderByExpression = Expression.Lambda<Func<int, int>>(d1Param, d1Param);

// End of inner OrderByDescending expression

// Find the "right" overload of Enumerable.OrderByDescending... Another pain.
MethodInfo orderByDescendingTSourceTKey = (from x in typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
                                            where x.Name == nameof(Enumerable.OrderByDescending)
                                            let args = x.GetGenericArguments()
                                            where args.Length == 2
                                            let pars = x.GetParameters()
                                            where pars.Length == 2 &&
                                                pars[0].ParameterType == typeof(IEnumerable<>).MakeGenericType(args[0]) &&
                                                pars[1].ParameterType == typeof(Func<,>).MakeGenericType(args[0], args[1])
                                            select x).Single();

// Make the generic overload of Enumerable.OrderByDescending "specific" for using with Func<int, int>
MethodInfo orderByDescendingInt32Int32 = orderByDescendingTSourceTKey.MakeGenericMethod(typeof(int), typeof(int));

// Note that Enumerable.OrderByDescending is a static method, the first parameter is the IEnumerable, the second is the Func<,>
// Enumerable.OrderByDescending(Enumerable.Select(...), d1 => d1)
MethodCallExpression orderByDescendingCall = Expression.Call(orderByDescendingInt32Int32, selectCall, orderByExpression);

// Find the "right" overload of Enumerable.First... Third big pain.
MethodInfo firstTSource = (from x in typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
                            where x.Name == nameof(Enumerable.First)
                            let args = x.GetGenericArguments()
                            where args.Length == 1
                            let pars = x.GetParameters()
                            where pars.Length == 1 &&
                                pars[0].ParameterType == typeof(IEnumerable<>).MakeGenericType(args[0])
                            select x).Single();

// Make the generic overload of Enumerable.OrderByDescending "specific" for using with int
MethodInfo firstInt32 = firstTSource.MakeGenericMethod(typeof(int));

// Note that Enumerable.First is a static method, the first parameter is the IEnumerable
// Enumerable.First(Enumerable.OrderByDescending(...))
MethodCallExpression firstCall = Expression.Call(firstInt32, orderByDescendingCall);