gpt4 book ai didi

c# - 创建排序 Func、IOrderedQueryable>?

转载 作者:太空狗 更新时间:2023-10-30 01:05:17 24 4
gpt4 key购买 nike

我想创建一个排序通用 Func Creating Func<IQueryable<T>, IOrderedQueryable<T>>在扩展方法中:

public static Func<IQueryable<T>, IOrderedQueryable<T>> GetOrderByFunc<T>(this KeyValuePair<string, SortingType> keyValuePair)
{
//I expect the following result
//Func<IQueryable<T>, IOrderedQueryable<T>> orderby = q => q.OrderByDescending(c => c.Name);

//keyValuePair.Key is name of property in type of T that I should sort T by it
switch (keyValuePair.Value)
{
case SortingType.Ascending:
// Creating Ascending Sorting Func
break;

case SortingType.Descending:
// Creating Descending Sorting Func
break;

default :
break;
}
}

你能指导我吗,我该怎么做?

编辑:

此排序还包含 T 的导航属性的计数。
例如:

// keyValuePair.Key equals "User.Count"
// User is a navigation property of T
Func<IQueryable<T>, IOrderedQueryable<T>> orderby = q => q.OrderByDescending(c => c.User.Count);

编辑:

我改变了GetSelector如下,但是bodyExpression出现了异常.

public static Expression GetSelector<T>(string propertyName)
{
ParameterExpression parameter = Expression.Parameter(typeof(T));
if (propertyName.Contains("."))
{
propertyName = propertyName.Substring(0, propertyName.IndexOf("."));
Type navigationPropertyCollectionType = typeof(T).GetProperty(propertyName).PropertyType;

if (navigationPropertyCollectionType.GetGenericTypeDefinition() == typeof(ICollection<>))
{
Expression countParameter = Expression.Parameter(navigationPropertyCollectionType, "c");
MemberExpression countExpression = Expression.Property(countParameter, "Count");
//Exception: Instance property 'Users(ICollection`1)' is not defined for type 'System.Int32'
var bodyExpression = Expression.Property(countExpression, propertyName, countParameter);
return Expression.Lambda(bodyExpression, parameter);
}
}
MemberExpression bodyMemberExpression = Expression.Property(parameter, typeof(T).GetProperty(propertyName));
return Expression.Lambda(bodyMemberExpression, parameter);
}

最佳答案

因此,我们首先需要的是一种方法,该方法可以获取选择器表达式,在给定属性名称时选择该属性值。它需要从头开始构建表达式:

public static Tuple<Expression, Type> GetSelector<T>(IEnumerable<string> propertyNames)
{
var parameter = Expression.Parameter(typeof(T));
Expression body = parameter;

foreach (var property in propertyNames)
{
body = Expression.Property(body,
body.Type.GetProperty(property));
}

return Tuple.Create(Expression.Lambda(body, parameter) as Expression
, body.Type);
}

请注意,由于这会导致属性链,因此该方法还会返回最终属性的类型,因为从调用者的角度来看,这不是特别容易访问的信息。

因为调用 Selector 时我们不知道属性的返回类型 所以我们别无选择,只能将此方法的返回类型保留为 Expression .我们不能将它转换为 Expression<Func<T, Something>> .我们可以让它返回 Expression<Func<T, object>> ,这适用于所有选择引用类型的属性,但它无法装箱值类型,因此在这些情况下会抛出运行时异常。

现在,因为我们不知道该表达式的确切类型,所以我们不能调用 OrderByOrderByDescending直接地。我们需要通过反射获取这些方法并使用 MakeGenericMethod以便可以根据使用反射对该属性的检查,使用正确的类型创建它们。

public static Func<IQueryable<T>, IOrderedQueryable<T>> GetOrderByFunc<T>(
this Tuple<IEnumerable<string>, SortingType> sortCriteria)
{
var selector = GetSelector<T>(sortCriteria.Item1);
Type[] argumentTypes = new[] { typeof(T), selector.Item2 };

var orderByMethod = typeof(Queryable).GetMethods()
.First(method => method.Name == "OrderBy"
&& method.GetParameters().Count() == 2)
.MakeGenericMethod(argumentTypes);
var orderByDescMethod = typeof(Queryable).GetMethods()
.First(method => method.Name == "OrderByDescending"
&& method.GetParameters().Count() == 2)
.MakeGenericMethod(argumentTypes);

if (sortCriteria.Item2 == SortingType.Descending)
return query => (IOrderedQueryable<T>)
orderByDescMethod.Invoke(null, new object[] { query, selector.Item1 });
else
return query => (IOrderedQueryable<T>)
orderByMethod.Invoke(null, new object[] { query, selector.Item1 });
}

关于c# - 创建排序 Func<IQueryable<T>、IOrderedQueryable<T>>?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19412663/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com