orderby
매개 변수로받는 값 을 사용하여 전달 된 인수를 어떻게 지정 합니까?
전의:
List<Student> existingStudends = new List<Student>{ new Student {...}, new Student {...}}
현재 구현 :
List<Student> orderbyAddress = existingStudends.OrderBy(c => c.Address).ToList();
대신 c.Address
매개 변수로 어떻게 사용할 수 있습니까?
예
string param = "City";
List<Student> orderbyAddress = existingStudends.OrderByDescending(c => param).ToList();
답변
여기에 반사를 사용하는 가능성이 있습니다 …
var param = "Address";
var propertyInfo = typeof(Student).GetProperty(param);
var orderByAddress = items.OrderBy(x => propertyInfo.GetValue(x, null));
답변
약간의 리플렉션을 사용하여 다음과 같이 표현식 트리를 구성 할 수 있습니다 (확장 방법입니다).
public static IQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string orderByProperty,
bool desc)
{
string command = desc ? "OrderByDescending" : "OrderBy";
var type = typeof(TEntity);
var property = type.GetProperty(orderByProperty);
var parameter = Expression.Parameter(type, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExpression = Expression.Lambda(propertyAccess, parameter);
var resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { type, property.PropertyType },
source.Expression, Expression.Quote(orderByExpression));
return source.Provider.CreateQuery<TEntity>(resultExpression);
}
orderByProperty
정렬 할 속성 이름이며에 대한 매개 변수로 true를 전달하면 desc
내림차순으로 정렬됩니다. 그렇지 않으면 오름차순으로 정렬됩니다.
이제 할 수 existingStudents.OrderBy("City",true);
있거나existingStudents.OrderBy("City",false);
답변
@Icarus 의 답변 을 확장하려면 확장 메서드의 반환 유형이 IQueryable 대신 IOrderedQueryable이되도록하려면 다음과 같이 결과를 간단히 캐스팅 할 수 있습니다.
public static IOrderedQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string orderByProperty, bool desc)
{
string command = desc ? "OrderByDescending" : "OrderBy";
var type = typeof(TEntity);
var property = type.GetProperty(orderByProperty);
var parameter = Expression.Parameter(type, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExpression = Expression.Lambda(propertyAccess, parameter);
var resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { type, property.PropertyType },
source.Expression, Expression.Quote(orderByExpression));
return (IOrderedQueryable<TEntity>)source.Provider.CreateQuery<TEntity>(resultExpression);
}
답변
1) System.Linq.Dynamic 설치
2) 다음 코드 추가
public static class OrderUtils
{
public static string ToStringForOrdering<T, TKey>(this Expression<Func<T, TKey>> expression, bool isDesc = false)
{
var str = expression.Body.ToString();
var param = expression.Parameters.First().Name;
str = str.Replace("Convert(", "(").Replace(param + ".", "");
return str + (isDesc ? " descending" : "");
}
}
3) Lambda 기능 선택을위한 스위치 작성
public static class SortHelper
{
public static Expression<Func<UserApp, object>> UserApp(string orderProperty)
{
orderProperty = orderProperty?.ToLowerInvariant();
switch (orderProperty)
{
case "firstname":
return x => x.PersonalInfo.FirstName;
case "lastname":
return x => x.PersonalInfo.LastName;
case "fullname":
return x => x.PersonalInfo.FirstName + x.PersonalInfo.LastName;
case "email":
return x => x.Email;
}
}
}
4) 도우미 사용
Dbset.OrderBy(SortHelper.UserApp("firstname").ToStringForOrdering())
5) pagging ( PagedList ) 과 함께 사용할 수 있습니다.
public virtual IPagedList<T> GetPage<TOrder>(Page page, Expression<Func<T, bool>> where, Expression<Func<T, TOrder>> order, bool isDesc = false,
params Expression<Func<T, object>>[] includes)
{
var orderedQueryable = Dbset.OrderBy(order.ToStringForOrdering(isDesc));
var query = orderedQueryable.Where(where).GetPage(page);
query = AppendIncludes(query, includes);
var results = query.ToList();
var total = Dbset.Count(where);
return new StaticPagedList<T>(results, page.PageNumber, page.PageSize, total);
}
설명
System.Linq.Dynamic을 사용하면 OrderBy 메서드에서 문자열 값을 설정할 수 있습니다. 그러나이 확장 내에서 문자열은 Lambda로 구문 분석됩니다. 그래서 Lambda를 문자열로 구문 분석하고 OrderBy 메서드에 제공하면 작동 할 것이라고 생각했습니다. 그리고 작동합니다!
답변
private Func<T, object> GetOrderByExpression<T>(string sortColumn)
{
Func<T, object> orderByExpr = null;
if (!String.IsNullOrEmpty(sortColumn))
{
Type sponsorResultType = typeof(T);
if (sponsorResultType.GetProperties().Any(prop => prop.Name == sortColumn))
{
System.Reflection.PropertyInfo pinfo = sponsorResultType.GetProperty(sortColumn);
orderByExpr = (data => pinfo.GetValue(data, null));
}
}
return orderByExpr;
}
public List<T> OrderByDir<T>(IEnumerable<T> source, string dir, Func<T, object> OrderByColumn)
{
return dir.ToUpper() == "ASC" ? source.OrderBy(OrderByColumn).ToList() : source.OrderByDescending(OrderByColumn).ToList();``
}
// Call the code like below
var orderByExpression= GetOrderByExpression<SearchResultsType>(sort);
var data = OrderByDir<SponsorSearchResults>(resultRecords, SortDirectionString, orderByExpression);
답변
조건부 내림차순을 처리하기 위해 제가 생각해 낸 것이 있습니다. 이를 keySelector
동적으로 func 를 생성하는 다른 방법과 결합 할 수 있습니다.
public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source,
System.Linq.Expressions.Expression<Func<TSource, TKey>> keySelector,
System.ComponentModel.ListSortDirection sortOrder
)
{
if (sortOrder == System.ComponentModel.ListSortDirection.Ascending)
return source.OrderBy(keySelector);
else
return source.OrderByDescending(keySelector);
}
용법:
//imagine this is some parameter
var direction = System.ComponentModel.ListSortDirection.Ascending;
query = query.OrderBy(ec => ec.MyColumnName, direction);
이렇게하면 .OrderBy
새 매개 변수를 사용 하여이 확장을 IQueryable에 연결할 수 있습니다 .
// perhaps passed in as a request of user to change sort order
// var direction = System.ComponentModel.ListSortDirection.Ascending;
query = context.Orders
.Where(o => o.Status == OrderStatus.Paid)
.OrderBy(ec => ec.OrderPaidUtc, direction);
답변
string
질문에서 요청한대로 를 통과 할 수는 없지만 여전히 작동 할 수 있습니다.
이 OrderByDescending
메서드는를 사용 Func<TSource, TKey>
하므로 다음과 같이 함수를 다시 작성할 수 있습니다.
List<Student> QueryStudents<TKey>(Func<Student, TKey> orderBy)
{
return existingStudents.OrderByDescending(orderBy).ToList();
}
, 및 / 또는 OrderByDescending
을 취하는 다른 오버로드 도 있습니다 . 당신은 또한 그것들을 조사하고 그들이 당신에게 유용한 것을 제공하는지 볼 수 있습니다.Expression<Func<TSource, TKey>>
IComparer<TKey>