我查看了这个问题的其他SO版本,但似乎某种方法的转换适用于其他人。我不确定我在这里做错了什么。我是Linq的Expression Building部分的新手。
我的扩展方法如下:
void Main()
{
var people = LoadData().AsQueryable();
var expression = people.PropertySelector<Person>("LastName");
expression.Should().BeOfType(typeof(Expression<Func<Person, object>>));
var result = people.OrderBy(expression);
}
public static class Extensions
{
public static Expression<Func<T, object>> PropertySelector<T>(this IEnumerable<T> collection, string propertyName)
{
if (string.IsNullOrWhiteSpace(propertyName))
{
throw new ArgumentException(nameof(propertyName));
}
var properties = typeof(T).GetProperties();
if (!properties.Any(p => p.Name == propertyName))
{
throw new ObjectNotFoundException($"Property: {propertyName} not found for type [{typeof(T).Name}]");
}
var propertyInfo = properties.Single(p => p.Name == propertyName);
var alias = Expression.Parameter(typeof(T), "_");
var property = Expression.Property(alias, propertyInfo);
var funcType = typeof(Func<,>).MakeGenericType(typeof(T), propertyInfo.PropertyType);
var lambda = Expression.Lambda(funcType, property, alias);
return (Expression<Func<T, object>>)lambda;
}
}
#region
private Random rand = new Random();
// Define other methods and classes here
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
public IEnumerable<Person> LoadData()
{
IList<Person> people = new List<Person>();
for (var i = 0; i < 15; i++)
{
people.Add(new Person
{
FirstName = $"FirstName {i}",
LastName = $"LastName {i}",
Age = rand.Next(1, 100)
});
}
return people;
}
#endregion
我在演员阵容中获得了一个例外。此时T
类型为Person
,object
为string
。我的lambda.GetType()
报告的类型为Expression<Func<Person, string>>
,例外情况为:
Unable to cast object of type 'System.Linq.Expressions.Expression`1[System.Func`2[UserQuery+Person,System.String]]' to type 'System.Linq.Expressions.Expression`1[System.Func`2[UserQuery+Person,System.Object]]'.
我的演员怎么样?感谢。
编辑: 我更新了我在LinqPad中玩的完整代码。我只是想弄清楚是否有一种通过传入属性名称生成lambda表达式的简单方法。我之前做过类似的事情,但我只是在属性名称上进行切换,然后使用lambda语法动态创建OrderBy查询。
严格来说,我正在努力学习如何使用Expression静态方法来获得与下面示例相同的结果。我试图模仿下面的通过扩展方法。但它不一定是这样。在LinqPad中逛逛时最简单的尝试。
Expression<Func<Loan, object>> sortExpression;
switch (propertyFilter)
{
case "Age":
sortExpression = (l => l.Age);
break;
case "LastName":
sortExpression = (l => l.LastName);
break;
default:
sortExpression = (l => l.FirstName);
break;
}
var sortedLoans = loans.AsQueryable().OrderBy(sortExpression);
sortedLoans.Dump("Filtered Property Result");
答案 0 :(得分:1)
您的代码正在创建if (0 % 3 === 0) // remainder is 0, so it is true
if (1 % 3 === 0) // remainder is 1, so it is false
if (2 % 3 === 0) // remainder is 2, so it is false
if (3 % 3 === 0) // remainder is 0, so it is true
,因为您正在使用
Func<UserQuery, String>
如果您想要返回var propertyInfo = properties.Single(p => p.Name == propertyName);
var funcType = typeof(Func<,>).MakeGenericType(typeof(T), propertyInfo.PropertyType);
,请创建Func<T, object>
,而不是Func<T, object>
,否则更好的解决方案是使用Func<T, (reflected property type)>
并创建完全通用的功能
答案 1 :(得分:1)
要保持当前的方法签名,您可以这样做:
var funcType = typeof(Func<,>).MakeGenericType(typeof(T), typeof(object));
var typeAs = Expression.TypeAs(property, typeof(object));
var lambda = Expression.Lambda(funcType, typeAs, alias);
更好的方法是将方法更改为
public static Expression<Func<T, Tout>> PropertySelector<T, Tout>(this IEnumerable<T> collection, string propertyName)
{
if (string.IsNullOrWhiteSpace(propertyName))
{
throw new ArgumentException(nameof(propertyName));
}
var properties = typeof(T).GetProperties();
if (!properties.Any(p => p.Name == propertyName))
{
throw new ObjectNotFoundException($"Property: {propertyName} not found for type [{typeof(T).Name}]");
}
var propertyInfo = properties.Single(p => p.Name == propertyName);
var alias = Expression.Parameter(typeof(T), "_");
var property = Expression.Property(alias, propertyInfo);
var funcType = typeof(Func<,>).MakeGenericType(typeof(T), propertyInfo.PropertyType);
var lambda = Expression.Lambda(funcType, property, alias);
return (Expression<Func<T, Tout>>)lambda;
}
并用
调用它 var expression = people.PropertySelector<Person, string>("LastName");
答案 2 :(得分:0)
我得到了我想要的结果。在@Gusman,@ IvanStoev和@PetSerAl的评论之后,我得到了它的功能。我可以继续探索和学习。非常感谢你。最终结果是模板化Propertytype。
user