위의 소스 내용을 보면 Sort 메소드는 확장메소드입니다. 그 파라미터 값으로 SQL 의 정렬 문법과 동일하게
필드명을 먼저 기재하고, 정렬에 대해 ASC 또는 DESC 로 오름차순 또는 내림차순을 정의할 수 있습니다.
이제 Sort 에 대한 확장 메소드를 구현해 볼까요?
sortExpression!s 파라미터값을 가지고 루프를 돌며, 새로운
comparers 를 생성합니다.
public static void Sort<T>(this List<T> list, string sortExpression)
{
string[] sortExpressions = sortExpression.Split(new string[] { "," },
StringSplitOptions.RemoveEmptyEntries);
List<GenericComparer> comparers = new List<GenericComparer>();
foreach (string sortExpress in sortExpressions)
{
string sortProperty = sortExpress.Trim().Split(' ')[0].Trim();
string sortDirection = sortExpress.Trim().Split(' ')[1].Trim();
Type type = typeof(T);
PropertyInfo PropertyInfo = type.GetProperty(sortProperty);
if (PropertyInfo == null)
{
PropertyInfo[] props = type.GetProperties();
foreach (PropertyInfo info in props)
{
if (info.Name.ToString().ToLower() == sortProperty.ToLower())
{
PropertyInfo = info;
break;
}
}
if (PropertyInfo == null)
{
throw new Exception(String.Format("{0} is not a valid property of type:
\"{1}\"", sortProperty, type.Name));
}
}
SortDirection SortDirection = SortDirection.Ascending;
if (sortDirection.ToLower() == "asc" || sortDirection.ToLower() == "ascending")
{
SortDirection = SortDirection.Ascending;
}
else if (sortDirection.ToLower() == "desc" ||
sortDirection.ToLower() == "descending")
{
SortDirection = SortDirection.Descending;
}
else
{
throw new Exception("Valid SortDirections are:
asc, ascending, desc and descending");
}
comparers.Add(new GenericComparer { SortDirection = SortDirection,
PropertyInfo = PropertyInfo, comparers = comparers });
}
listSort(comparers[0].Compare);
}
아래는 두개의 요소를 비교하는 GenericComparer 클래스를 구현한 것입니다.
public class GenericComparer
{
public List<GenericComparer> comparers { get; set; }
int level = 0;
public SortDirection SortDirection { get; set; }
public PropertyInfo PropertyInfo { get; set; }
public int Compare<T>(T t1, T t2)
{
int ret = 0;
if (level >= comparers.Count)
return 0;
object t1Value = comparers[level].PropertyInfo.GetValue(t1, null);
object t2Value = comparers[level].PropertyInfo.GetValue(t2, null);
if (t1 == null || t1Value == null)
{
if (t2 == null || t2Value == null)
{
ret = 0;
}
else
{
ret = -1;
}
}
else
{
if (t2 == null || t2Value == null)
{
ret = 1;
}
else
{
ret = ((IComparable)t1Value).CompareTo(((IComparable)t2Value));
}
}
if (ret == 0)
{
level += 1;
ret = Compare(t1, t2);
level -= 1;
}
else
{
if (comparers[level].SortDirection == SortDirection.Descending)
{
ret *= -1;
}
}
return ret;
}
}
위의 클래스 및 메소드를 이용하여 사용방법을 알아보죠.
public class ExampleUser
{
public DateTime Birthday { get; set; }
public string Firstname { get; set; }
}
객체를 담기 위해 필드와 메소드를 구현했습니다.
List<ExampleUser> userlist = new List<ExampleUser>();
userlist.Add(new ExampleUser
{ Birthday = new DateTime(1988, 10, 1), Firstname = "Bryan" });
userlist.Add(new ExampleUser
{ Birthday = new DateTime(1986, 11, 4), Firstname = "Michael" });
userlist.Add(new ExampleUser
{ Birthday = new DateTime(1977, 2, 2), Firstname = "Arjan" });
userlist.Add(new ExampleUser
{ Birthday = new DateTime(1990, 6, 13), Firstname = "Pieter" });
userlist.Add(new ExampleUser
{ Birthday = new DateTime(1988, 10, 1), Firstname = "Ruben" });
userlist.Add(new ExampleUser
{ Birthday = new DateTime(1987, 8, 21), Firstname = "Bastiaan" });
userlist.Add(new ExampleUser
{ Birthday = new DateTime(1987, 8, 21), Firstname = "Pieter" });
제네릭 List 를 이용하여 객체를 위와 같이 Add 메소드로 추가했습니다.
정렬을 하지 않고 할당된 값 그대로 출력하고자 한다면??? Unsorted:
string unsorted = "Unsorted: ";
foreach (ExampleUser user in userlist)
{
unsorted += String.Format("{0} / {1} {2}", user.Birthday.ToString
("dd-MM-yyyy"), user.Firstname, Environment.NewLine);
}
첫번째 이름의 성을 정렬하고자 한다면? Firstname asc
userlist.Sort("Firstname asc");
string sorted1 = "Sorted by Firstname asc: " + Environment.NewLine;
foreach (ExampleUser user in userlist)
{
sorted1 += String.Format("{0} / {1} {2}", user.Birthday.ToString
("dd-MM-yyyy"), user.Firstname, Environment.NewLine);
}
성과 생일을 둘다 정렬하고자 한다면? Firstname asc, Birthday desc
userlist.Sort("Firstname asc, Birthday desc");
string sorted2 = "Sorted by Firstname asc, Birtday desc: " + Environment.NewLine;
foreach (ExampleUser user in userlist)
{
sorted2 += String.Format("{0} / {1} {2}", user.Birthday.ToString
("dd-MM-yyyy"), user.Firstname, Environment.NewLine);
}
역반대로 생일을 먼저 asc 순서를 하고 그 다음 "성" 을 asc 문서로 하고자 한다면? Birthday asc, Firstname asc
userlist.Sort("Birthday asc, Firstname asc");
string sorted3 = "Sorted by Birthday ascending,
Firstname asc: " + Environment.NewLine;
foreach (ExampleUser user in userlist)
{
sorted3 += String.Format("{0} / {1} {2}", user.Birthday.ToString
("dd-MM-yyyy"), user.Firstname, Environment.NewLine);
}
위의 클래스 및 메소드에 대해서 상세히 설명을 하지 않았는데요. 이는 vs 툴을 가지고 있으시다면 디버깅을 통해서 하나 하나 찾아가시면서 구현한 부분에 대해 이해를 얻으시면 될것 같습니다.
참고로 원문 내용과 동일하게 번역하여 설명을 하지 않았으므로, 원문 사이트 경로에 가셔서 원문 작성자가 기재한
내용을 읽어 보시면 더욱더 도움이 될 것 입니다.
원문 작성자 : Bryan Sumter
원문 사이트 경로 : http://www.codeproject.com/KB/cs/GenericSorter.aspx
감사합니다.
posted by 심재운 (shimpark@gmail.com)
http://cafe.daum.net/aspdotnet/VY7/145