문자열에 “속성 정렬”의 이름이 있습니다. Lambda / Linq를 사용하여 객체 목록을 정렬해야합니다.
전의:
public class Employee
{
public string FirstName {set; get;}
public string LastName {set; get;}
public DateTime DOB {set; get;}
}
public void Sort(ref List<Employee> list, string sortBy, string sortDirection)
{
//Example data:
//sortBy = "FirstName"
//sortDirection = "ASC" or "DESC"
if (sortBy == "FirstName")
{
list = list.OrderBy(x => x.FirstName).toList();
}
}
- 필드 이름 (sortBy)을 확인하기 위해 많은 if를 사용하는 대신 정렬을 수행하는 더 확실한 방법이 있습니까?
- 정렬이 데이터 유형을 알고 있습니까?
답변
이것은 다음과 같이 수행 할 수 있습니다
list.Sort( (emp1,emp2)=>emp1.FirstName.CompareTo(emp2.FirstName) );
.NET 프레임 워크는 람다 (emp1,emp2)=>int
를Comparer<Employee>.
이것은 강력하게 타이핑되는 장점이 있습니다.
답변
당신이 할 수있는 한 가지는 Sort
람다를 더 잘 사용하도록 변경 하는 것입니다.
public enum SortDirection { Ascending, Descending }
public void Sort<TKey>(ref List<Employee> list,
Func<Employee, TKey> sorter, SortDirection direction)
{
if (direction == SortDirection.Ascending)
list = list.OrderBy(sorter);
else
list = list.OrderByDescending(sorter);
}
이제 Sort
메소드를 호출 할 때 정렬 할 필드를 지정할 수 있습니다 .
Sort(ref employees, e => e.DOB, SortDirection.Descending);
답변
Reflection을 사용하여 속성 값을 얻을 수 있습니다.
list = list.OrderBy( x => TypeHelper.GetPropertyValue( x, sortBy ) )
.ToList();
TypeHelper에는 다음과 같은 정적 메소드가 있습니다.
public static class TypeHelper
{
public static object GetPropertyValue( object obj, string name )
{
return obj == null ? null : obj.GetType()
.GetProperty( name )
.GetValue( obj, null );
}
}
VS2008 샘플 라이브러리 에서 Dynamic LINQ를 볼 수도 있습니다 . IEnumerable 확장을 사용하여 List를 IQueryable로 캐스팅 한 다음 Dynamic link OrderBy 확장을 사용할 수 있습니다.
list = list.AsQueryable().OrderBy( sortBy + " " + sortDirection );
답변
이것이 내 문제를 해결 한 방법입니다.
List<User> list = GetAllUsers(); //Private Method
if (!sortAscending)
{
list = list
.OrderBy(r => r.GetType().GetProperty(sortBy).GetValue(r,null))
.ToList();
}
else
{
list = list
.OrderByDescending(r => r.GetType().GetProperty(sortBy).GetValue(r,null))
.ToList();
}
답변
식으로 주문 작성은 여기에서 읽을 수 있습니다
링크의 페이지에서 뻔뻔스럽게 도난당했습니다.
// First we define the parameter that we are going to use
// in our OrderBy clause. This is the same as "(person =>"
// in the example above.
var param = Expression.Parameter(typeof(Person), "person");
// Now we'll make our lambda function that returns the
// "DateOfBirth" property by it's name.
var mySortExpression = Expression.Lambda<Func<Person, object>>(Expression.Property(param, "DateOfBirth"), param);
// Now I can sort my people list.
Person[] sortedPeople = people.OrderBy(mySortExpression).ToArray();
답변
리플렉션을 사용하여 속성에 액세스 할 수 있습니다.
public List<Employee> Sort(List<Employee> list, String sortBy, String sortDirection)
{
PropertyInfo property = list.GetType().GetGenericArguments()[0].
GetType().GetProperty(sortBy);
if (sortDirection == "ASC")
{
return list.OrderBy(e => property.GetValue(e, null));
}
if (sortDirection == "DESC")
{
return list.OrderByDescending(e => property.GetValue(e, null));
}
else
{
throw new ArgumentOutOfRangeException();
}
}
노트
- 왜 목록을 참조로 전달합니까?
- 정렬 방향으로 열거 형을 사용해야합니다.
- 속성 이름 대신 문자열로 정렬 할 속성을 지정하는 람다 식을 전달하면 훨씬 깨끗한 솔루션을 얻을 수 있습니다.
- 내 예제 list == null에서 NullReferenceException이 발생 하므로이 경우를 포착해야합니다.
답변
유형이 구현하는 경우 Sort는 IComparable 인터페이스를 사용합니다. 또한 사용자 정의 IComparer를 구현하여 if를 피할 수 있습니다.
class EmpComp : IComparer<Employee>
{
string fieldName;
public EmpComp(string fieldName)
{
this.fieldName = fieldName;
}
public int Compare(Employee x, Employee y)
{
// compare x.fieldName and y.fieldName
}
}
그리고
list.Sort(new EmpComp(sortBy));
