【发布时间】:2016-05-03 19:11:46
【问题描述】:
我查看了这个问题的其他 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");
【问题讨论】:
-
类是不变的。因此,即使允许从
TFunc1转换为TFunc2,您也不能将Expression<TFunc1>转换为Expression<TFunc2>。 -
你想用这个方法完成什么?我试图理解你为什么需要 Func
。您是否尝试根据特定属性进行过滤? -
您可以通过
Expression.Convert(property, typeof (object))投射到对象。 -
你真的需要输出为
Expression<Func<T, object>>吗?或Expression<Func<T, TProperty>>? -
加入其他 cmets。扩展方法也很奇怪——它“扩展”了
IEnumerable<T>实例(collection参数)但不使用它。您最好展示一个示例预期用途。
标签: c# linq lambda extension-methods linq-expressions