2013-06-06 2 views
0

У меня есть тот классC# сортировать список пользовательского класса

public class MyItem 
{ 
    public Order OrderItem { get; set; } 
    public string Status { get; set; } 
} 

Status свойства может иметь значения Error, Pending, Success

Я хочу, чтобы отсортировать List<MyItem>() объект базирование на Status собственности.

Я знаю, что я могу заменить тип Status собственности от string до int, а затем вместо Error, Pending, Success значений я могу иметь 1, 2, 3 и тогда операция сортировки проста. Но мне интересно, как это сделать, если мы должны выполнить сортировку на основе свойства типа string.

Возможный заказ:

Error, Pending, Success или Success, Pending, Error

, как сделать это с помощью LINQ?

+8

Почему строки и не перечисления? – Leri

+2

Вы можете написать пользовательский 'IComparer ', но, как @PLB говорит, почему бы не использовать перечисление? – Jodrell

ответ

3

Самый простой способ, вероятно, реализовать интерфейс IComparable<T>. Внедрение этого интерфейса в вашем классе MyItem гарантирует, что при заказе списка экземпляров MyItem будет использоваться порядок, указанный в методе CompareTo. Для вашего случая использования, это приведет в коде следующим образом:

public class MyItem : IComparable<MyItem> 
{ 
    public string OrderItem { get; set; } 
    public string Status { get; set; } 

    public int CompareTo(MyItem other) 
    { 
     if (other == null) 
     { 
      return 1; 
     } 

     if (other.Status == this.Status) 
     { 
      return 0; 
     } 

     var statusAsInt = this.Status == "Error" ? 0 : (this.Status == "Pending" ? 1 : 2); 
     var otherStatusAsInt = other.Status == "Error" ? 0 : (other.Status == "Pending" ? 1 : 2); 

     if (statusAsInt == otherStatusAsInt) 
     { 
      return 0; 
     } 

     return statusAsInt < otherStatusAsInt ? -1 : 1; 
    } 
} 

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
     var myItems = new List<MyItem> { new MyItem { Status = "Pending" }, new MyItem { Status = "Error" }, new MyItem { Status = "Success " } }; 

     myItems.Sort(); 

     foreach (var myItem in myItems) 
     { 
      Console.WriteLine(myItem.Status); 
     }  
    } 
} 
5

Вместо этого я бы использовал enum, который по умолчанию дает каждому статусу целочисленное значение, например.

public enum Status 
{ 
    Success, 
    Pending, 
    Error 
} 

var sortedList = myList.OrderBy(x => x.Status); 
// sort by Success, Pending and then Error 
var sortedList = myList.OrderByDescending(x => x.Status); 
// sort by Error, Pending, Success 

Вы можете преобразовать существующие строки в enum довольно легко:

var status = (Status)Enum.Parse(typeof(Status), statusString); 
+0

Я уже делал это, но мне интересно узнать о случае строки – Tony

+1

@Tony, если вы * имели * для сравнения 'string', вам нужно написать собственный класс' IComparer ' или сделать свой класс 'MyItem' реализовать 'IComparable '. Тем не менее, я определенно хотел бы перейти на «enum» в этом случае, это правильный путь. – James

1

Я думаю, что было бы лучше, чтобы изменить тип состояния и заменить строку на перечисление. Затем вы можете выбрать нужный заказ, присвоив значения различным членам вашего перечисления или напрямую заказать этот член по своему методу заказа и сохранить читаемое свойство.

1

Как порядки случается алфавитный, вы можете сделать простой

var result = myList.OrderBy(item => item.Status); 

или

var result = myList.OrderByDescending(item => item.Status); 

Однако, если вы переименуете «Успех» как «Завершить», тогда он сломается, и в этом случае я бы рекомендовал один из предложенных ответов enum.

2

Можно определить словарь, отражающий необходимый для заказа

Dictionary<string, int> ordering = new Dictionary<string, int> { 
    { "Error", 1 }, 
    { "Pending", 2 }, 
    ... 
} 

var sortedList = myList.OrderBy(x => ordering[x.Status]); 
4

Его лучше разобрать на enum, но вы могли бы сделать собственный компаратор,

var customComparer = Comparer<string>.Create((x, y) => 
    { 
     ... 
    }); 

Вы можете чем передать сравнение в порядке и порядке по функциям, например,

var sortedList = myList.OrderBy(x => x.Status, customComparer); 
0

I wo пакетирования пойти на вариант Enum, но при условии, что это не ваш предпочтительный вариант вы можете попробовать следующее:

Вы можете реализовать IComparable<MyItem> в классе MyItem

Там реализовать логику заказа в соответствии с Состояние свойства. Если два статуса равны, вы даже можете заказать OrderItem, если это вам подходит.

Если вам нужен пример, не стесняйтесь сказать

0

Вы можете передать .OrderBy() метод, который взвешивает строки, используя переключатель, как это:

 List<MyItem> lst = new List<MyItem>(); 

    lst.Add(new MyItem() { Status = "Pending" }); 
    lst.Add(new MyItem() { Status = "Error" }); 
    lst.Add(new MyItem() { Status = "Invalid String" }); 
    lst.Add(new MyItem() { Status = "Success" }); 

    var ascList = 
     lst.OrderBy((x) => { switch (x.Status) { case "Error": return 0; case "Pending": return 1; case "Success": return 3; default: return 4; } }); 

    var descList = 
     lst.OrderByDescending((x) => { switch (x.Status) { case "Error": return 0; case "Pending": return 1; case "Success": return 3; default: return 4; } }); 

    Console.WriteLine("Asc\n==="); 
    foreach (MyItem mi in ascList) 
    { 
     Console.WriteLine(mi.Status); 
    } 

    Console.WriteLine("\nDesc\n===="); 
    foreach (MyItem mi in descList) 
    { 
     Console.WriteLine(mi.Status); 
    } 
    }