在lambda表达式中查找属性名



我有一个编码问题要解决,我有点知道我应该遵循的路径,但仍然缺少一些东西。我的任务是修改代码,使其更通用,减少冗余。

整个类给出如下。这似乎有点愚蠢,问题是冗余本身。

using System; 
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace TestRedundance
{
public class EntityRedundance
{
public class Entity
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime ValidFrom { get; set; }
}
private void AddSorting(IQueryable<Entity> query, List<string> sortingColumns, bool orderDescending)
{
if (!sortingColumns.Any())
{
query = query.OrderBy(x => x.Name);
return;
}
foreach (var column in sortingColumns)
{
switch (column)
{
case "Name":
query = orderDescending ? query.OrderByDescending(x => x.Name) : query.OrderBy(x => x.Name);
break;
case "Description":
query = orderDescending ? query.OrderByDescending(x => x.Description) : query.OrderBy(x => x.Description);
break;
case "ValidFrom":
query = orderDescending ? query.OrderByDescending(x => x.ValidFrom) : query.OrderBy(x => x.ValidFrom);
break;
}
}
}
}
}

据我所知,冗余是在每个开关情况下重复相同的代码,只改变要排序的列。

我的意图是将其更改为单行,使用Reflection将我的实体的属性名称与列名进行比较,然后替换这一行的switch-case块。但是表达式不允许这样做。就像下面这行,因为它是错误的,所以被注释了。

//query = orderDescending ? query.OrderByDescending(x => 
//x.GetType().GetProperties() : query.OrderBy(x => x.Name);

我很感激你的建议。

许多谢谢。

您的代码有几个问题。首先,在动态添加要排序的列时保持强类型需要在方法中隐藏列选择lambda,以便无论列的类型如何,都具有一致的签名。其次,LINQ排序要求OrderBy后面跟着ThenBy进行链排序,这意味着您有另一个类型问题,因为ThenBy期望IOrderedQueryable<T>,因此分配给query将不起作用。第三,在方法返回后,给query赋值不会改变任何东西,因为它是AddSorting方法的一个参数,而OrderByThenBy方法返回的新对象将在方法返回时丢失。

因此,为了解决这些问题,首先我们可以创建一些辅助字典,将bool(orderDescending)映射到每种类型列的特定排序方法,一个用于OrderBy,一个用于ThenBy:

static Dictionary<bool, Func<IQueryable<Entity>, Expression<Func<Entity, string>>, IOrderedQueryable<Entity>>> stringOrderByDirMap = new() {
{ false, Queryable.OrderBy<Entity, string> },
{ true, Queryable.OrderByDescending<Entity, string> },
};
static Dictionary<bool, Func<IOrderedQueryable<Entity>, Expression<Func<Entity, string>>, IOrderedQueryable<Entity>>> stringThenByDirMap = new() {
{ false, Queryable.ThenBy<Entity, string> },
{ true, Queryable.ThenByDescending<Entity, string> },
};
static Dictionary<bool, Func<IQueryable<Entity>, Expression<Func<Entity, DateTime>>, IOrderedQueryable<Entity>>> dateTimeOrderByDirMap = new() {
{ false, Queryable.OrderBy<Entity, DateTime> },
{ true, Queryable.OrderByDescending<Entity, DateTime> },
};
static Dictionary<bool, Func<IOrderedQueryable<Entity>, Expression<Func<Entity, DateTime>>, IOrderedQueryable<Entity>>> dateTimeThenByDirMap = new() {
{ false, Queryable.ThenBy<Entity, DateTime> },
{ true, Queryable.ThenByDescending<Entity, DateTime> },
};

使用这些,您可以创建一对字典(一个用于OrderBy,一个用于ThenBy),它们将列名映射到一个lambda函数,该函数接受bool,并返回一个lambda,该lambda将IQueryable<T>IOrderedQueryable<T>映射到相应列的IOrderedQueryable<T>:

static Dictionary<string, Func<bool, Func<IQueryable<Entity>, IOrderedQueryable<Entity>>>> firstSort = new() {
{ "Name", desc => q => stringOrderByDirMap[desc](q, e => e.Name) },
{ "Description", desc => q => stringOrderByDirMap[desc](q, e => e.Description) },
{ "ValidFrom", desc => q => dateTimeOrderByDirMap[desc](q, e => e.ValidFrom) },
};
static Dictionary<string, Func<bool, Func<IOrderedQueryable<Entity>, IOrderedQueryable<Entity>>>> thenSort = new() {
{ "Name", desc => q => stringThenByDirMap[desc](q, e => e.Name) },
{ "Description", desc => q => stringThenByDirMap[desc](q, e => e.Description) },
{ "ValidFrom", desc => q => dateTimeThenByDirMap[desc](q, e => e.ValidFrom) },
};
通过所有这些设置,您的AddSorting方法变成了
private IQueryable<Entity> AddSorting(IQueryable<Entity> query, List<string> sortingColumns, bool orderDescending) {
if (!sortingColumns.Any())
return query.OrderBy(x => x.Name);
IOrderedQueryable<Entity> sortedQuery = null;
foreach (var column in sortingColumns) {
if (sortedQuery == null)
sortedQuery = firstSort[column](orderDescending)(query);
else
sortedQuery = thenSort[column](orderDescending)(sortedQuery);
}

return sortedQuery;
}

考虑到只有三列的示例,使用反射来构建Expression树似乎有些多余,但是,您可以使用反射从列的类型和列表中填充firstSortthenSort字典,而不是对它们的初始值进行编码。您需要为每种可能的列类型编写适当的OrderByThenBy映射。

相关内容

  • 没有找到相关文章

最新更新