C# 无法使用列表手动创建Lambda表达式树<;T>;
我需要手动创建此lambda表达式的帮助。我无法通过正确创建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
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);