Comment sortinger une liste par une propriété dans l’object

J’ai une classe appelée Order qui possède des propriétés telles que OrderId , OrderDate , Quantity et Total . J’ai une liste de cette classe de Order :

 List objListOrder = new List(); GetOrderList(objListOrder); // fill list of orders 

Maintenant, je veux sortinger la liste en fonction d’une propriété de l’object Order , par exemple, je dois la sortinger par la date de la commande ou l’ID de la commande.

Comment puis-je le faire en C #?

La manière la plus simple de penser est d’utiliser Linq:

 List SortedList = objListOrder.OrderBy(o=>o.OrderDate).ToList(); 

Si vous devez sortinger la liste sur place, vous pouvez utiliser la méthode Sort , en passant un délégué Comparison :

 objListOrder.Sort((x, y) => x.OrderDate.CompareTo(y.OrderDate)); 

Si vous préférez créer une nouvelle séquence sortingée plutôt que de sortinger sur place, vous pouvez utiliser la méthode OrderBy de LINQ, comme indiqué dans les autres réponses.

Pour ce faire sans LINQ sur .Net2.0:

 List objListOrder = GetOrderList(); objListOrder.Sort( delegate(Order p1, Order p2) { return p1.OrderDate.CompareTo(p2.OrderDate); } ); 

Si vous êtes sur .Net3.0, la réponse de LukeH est ce que vous recherchez.

Pour sortinger sur plusieurs propriétés, vous pouvez toujours le faire dans un délégué. Par exemple:

 orderList.Sort( delegate(Order p1, Order p2) { int compareDate = p1.Date.CompareTo(p2.Date); if (compareDate == 0) { return p2.OrderID.CompareTo(p1.OrderID); } return compareDate; } ); 

Cela vous donnerait des dates ascendantes avec des ordonnances décroissantes .

Cependant, je ne recommanderais pas de coller des delegates car cela signifierait beaucoup d’endroits sans réutilisation du code. Vous devez implémenter un IComparer et le transmettre à votre méthode de Sort . Voir ici

 public class MyOrderingClass : IComparer { public int Compare(Order x, Order y) { int compareDate = x.Date.CompareTo(y.Date); if (compareDate == 0) { return x.OrderID.CompareTo(y.OrderID); } return compareDate; } } 

Et puis, pour utiliser cette classe IComparer, instanciez-la et transmettez-la à votre méthode de sorting:

 IComparer comparer = new MyOrderingClass(); orderList.Sort(comparer); 

Le moyen le plus simple de commander une liste est d’utiliser OrderBy

  List objListOrder = source.OrderBy(order => order.OrderDate).ToList(); 

Si vous souhaitez commander par plusieurs colonnes, suivez la requête SQL suivante.

 ORDER BY OrderDate, OrderId 

Pour ce faire, vous pouvez utiliser ThenBy comme suit.

  List objListOrder = source.OrderBy(order => order.OrderDate).ThenBy(order => order.OrderId).ToList(); 

Le faire sans Linq comme vous l’avez dit:

 public class Order : IComparable { public DateTime OrderDate { get; set; } public int OrderId { get; set; } public int CompareTo(object obj) { Order orderToCompare = obj as Order; if (orderToCompare.OrderDate < OrderDate || orderToCompare.OrderId < OrderId) { return 1; } if (orderToCompare.OrderDate > OrderDate || orderToCompare.OrderId > OrderId) { return -1; } // The orders are equivalent. return 0; } } 

Ensuite, appelez simplement .sort () sur votre liste de commandes

Une solution orientée object classique

Tout d’abord, je dois me rendre compte de la génialité de LINQ …. Maintenant que nous avons réussi

Une variation sur la réponse de JimmyHoffa. Avec les génériques, le paramètre CompareTo devient de type sécurisé.

 public class Order : IComparable { public int CompareTo( Order that ) { if ( that == null ) return 1; if ( this.OrderDate > that.OrderDate) return 1; if ( this.OrderDate < that.OrderDate) return -1; return 0; } } // in the client code // assume myOrders is a populated List myOrders.Sort(); 

Cette facilité de sorting par défaut est bien sûr réutilisable. C’est-à-dire que chaque client n’a pas besoin de réécrire de manière redondante la logique de sorting. Inverser le “1” et “-1” (ou les opérateurs logiques, votre choix) inverse l’ordre de sorting.

// Tri totalement générique à utiliser avec un quadrillage

 public List Sort_List(ssortingng sortDirection, ssortingng sortExpression, List data) { List data_sorted = new List(); if (sortDirection == "Ascending") { data_sorted = (from n in data orderby GetDynamicSortProperty(n, sortExpression) ascending select n).ToList(); } else if (sortDirection == "Descending") { data_sorted = (from n in data orderby GetDynamicSortProperty(n, sortExpression) descending select n).ToList(); } return data_sorted; } public object GetDynamicSortProperty(object item, ssortingng propName) { //Use reflection to get order type return item.GetType().GetProperty(propName).GetValue(item, null); } 

Voici une méthode générique d’extension LINQ qui ne crée pas de copie supplémentaire de la liste:

 public static void Sort(this List list, Func expression) where U : IComparable { list.Sort((x, y) => expression.Invoke(x).CompareTo(expression.Invoke(y))); } 

Pour l’utiliser:

 myList.Sort(x=> x.myProperty); 

J’ai récemment construit cette version supplémentaire qui accepte une ICompare , afin que vous puissiez personnaliser la comparaison. Cela s’est avéré utile quand j’ai eu besoin de faire un sorting de chaîne naturelle:

 public static void Sort(this List list, Func expression, IComparer comparer) where U : IComparable { list.Sort((x, y) => comparer.Compare(expression.Invoke(x), expression.Invoke(y))); } 

Utiliser LINQ

 objListOrder = GetOrderList() .OrderBy(o => o.OrderDate) .ToList(); objListOrder = GetOrderList() .OrderBy(o => o.OrderId) .ToList(); 
 //Get data from database, then sort list by staff name: List staffList = staffHandler.GetStaffMembers(); var sortedList = from staffmember in staffList orderby staffmember.Name ascending select staffmember; 

Une version améliorée de Roger.

Le problème avec GetDynamicSortProperty est que seuls les noms de propriété sont obtenus, mais que se passe-t-il si, dans GridView, nous utilisons les propriétés de navigation? il va envoyer une exception, car il trouve null.

Exemple:

“Employee.Company.Name;” va planter … car n’autorise que “Name” comme paramètre pour obtenir sa valeur.

Voici une version améliorée qui nous permet de sortinger par propriétés de navigation.

 public object GetDynamicSortProperty(object item, ssortingng propName) { try { ssortingng[] prop = propName.Split('.'); //Use reflection to get order type int i = 0; while (i < prop.Count()) { item = item.GetType().GetProperty(prop[i]).GetValue(item, null); i++; } return item; } catch (Exception ex) { throw ex; } } 

Vous pouvez faire quelque chose de plus générique à propos de la sélection des propriétés, tout en précisant le type que vous sélectionnez, dans votre cas, «Ordre»:

écris ta fonction comme générique:

 public List GetOrderList(IEnumerable orders, Func propertySelector) { return (from order in orders orderby propertySelector(order) select order).ToList(); } 

et ensuite l’utiliser comme ceci:

 var ordersOrderedByDate = GetOrderList(orders, x => x.OrderDate); 

Vous pouvez être encore plus générique et définir un type ouvert pour ce que vous voulez commander:

 public List OrderBy(IEnumerable collection, Func propertySelector) { return (from item in collection orderby propertySelector(item) select item).ToList(); } 

et l’utiliser de la même manière:

 var ordersOrderedByDate = OrderBy(orders, x => x.OrderDate); 

Quelle est une manière complexe, stupide et inutile de faire un style LINQ “OrderBy”, mais cela peut vous donner une idée de la manière dont il peut être implémenté de manière générique

S’il vous plaît laissez-moi compléter la réponse par @ LukeH avec un exemple de code, comme je l’ai testé, je crois qu’il peut être utile pour certains:

 public class Order { public ssortingng OrderId { get; set; } public DateTime OrderDate { get; set; } public int Quantity { get; set; } public int Total { get; set; } public Order(ssortingng orderId, DateTime orderDate, int quantity, int total) { OrderId = orderId; OrderDate = orderDate; Quantity = quantity; Total = total; } } public void SampleDataAndTest() { List objListOrder = new List(); objListOrder.Add(new Order("tu me paulo ", Convert.ToDateTime("01/06/2016"), 1, 44)); objListOrder.Add(new Order("ante laudabas", Convert.ToDateTime("02/05/2016"), 2, 55)); objListOrder.Add(new Order("ad ordinem ", Convert.ToDateTime("03/04/2016"), 5, 66)); objListOrder.Add(new Order("collocationem ", Convert.ToDateTime("04/03/2016"), 9, 77)); objListOrder.Add(new Order("que rerum ac ", Convert.ToDateTime("05/02/2016"), 10, 65)); objListOrder.Add(new Order("locorum ; cuius", Convert.ToDateTime("06/01/2016"), 1, 343)); Console.WriteLine("Sort the list by date ascending:"); objListOrder.Sort((x, y) => x.OrderDate.CompareTo(y.OrderDate)); foreach (Order o in objListOrder) Console.WriteLine("OrderId = " + o.OrderId + " OrderDate = " + o.OrderDate.ToSsortingng() + " Quantity = " + o.Quantity + " Total = " + o.Total); Console.WriteLine("Sort the list by date descending:"); objListOrder.Sort((x, y) => y.OrderDate.CompareTo(x.OrderDate)); foreach (Order o in objListOrder) Console.WriteLine("OrderId = " + o.OrderId + " OrderDate = " + o.OrderDate.ToSsortingng() + " Quantity = " + o.Quantity + " Total = " + o.Total); Console.WriteLine("Sort the list by OrderId ascending:"); objListOrder.Sort((x, y) => x.OrderId.CompareTo(y.OrderId)); foreach (Order o in objListOrder) Console.WriteLine("OrderId = " + o.OrderId + " OrderDate = " + o.OrderDate.ToSsortingng() + " Quantity = " + o.Quantity + " Total = " + o.Total); //etc ... } 

Aucune des réponses ci-dessus n’était assez générique pour moi, alors j’ai fait celle-ci:

 var someUserInputSsortingngValue = "propertyNameOfObject ie 'Quantity' or 'Date'"; var SortedData = DataToBeSorted .OrderBy(m => m.GetType() .GetProperties() .First(n => n.Name == someUserInputSsortingngValue) .GetValue(m, null)) .ToList(); 

Attention aux ensembles de données massifs cependant. C’est un code simple mais qui pourrait vous causer des problèmes si la collection est énorme et que le type d’object de la collection contient un grand nombre de champs. Le temps d’exécution est NxM où:

N = # d’éléments dans la collection

M = # de propriétés dans Object

 var obj = db.Items.Where... var orderBYItemId = obj.OrderByDescending(c => Convert.ToInt32(c.ID)); 

Utilisez LiNQ OrderBy

 List objListOrder=new List (); objListOrder=GetOrderList().OrderBy(o=>o.orderid).ToList(); 

Basé sur Comparer les GenericTypeTea:
Nous pouvons obtenir plus de flexibilité en ajoutant des indicateurs de sorting:

 public class MyOrderingClass : IComparer { public int Compare(Order x, Order y) { int compareDate = x.Date.CompareTo(y.Date); if (compareDate == 0) { int compareOrderId = x.OrderID.CompareTo(y.OrderID); if (OrderIdDescending) { compareOrderId = -compareOrderId; } return compareOrderId; } if (DateDescending) { compareDate = -compareDate; } return compareDate; } public bool DateDescending { get; set; } public bool OrderIdDescending { get; set; } } 

Dans ce scénario, vous devez l’instancier comme MyOrderingClass explicitement (plutôt qu’IComparer )
afin de définir ses propriétés de sorting:

 MyOrderingClass comparer = new MyOrderingClass(); comparer.DateDescending = ...; comparer.OrderIdDescending = ...; orderList.Sort(comparer); 

Du sharepoint vue des performances, le mieux est d’utiliser une liste sortingée afin que les données soient sortingées au fur et à mesure de leur ajout au résultat. D’autres approches nécessitent au moins une itération supplémentaire sur les données et la plupart créent une copie des données. Ainsi, non seulement les performances, mais l’utilisation de la mémoire seront également affectées. Ne serait pas un problème avec quelques centaines d’éléments, mais sera avec des milliers, en particulier dans les services où de nombreuses demandes simultanées peuvent faire le sorting en même temps. Jetez un coup d’œil à l’espace de noms System.Collections.Generic et choisissez une classe avec sorting au lieu de List.

Et évitez les implémentations génériques en utilisant la reflection lorsque cela est possible, cela peut également entraîner des problèmes de performances.

Toute personne travaillant avec des types nullables, Value est nécessaire pour utiliser CompareTo .

objListOrder.Sort((x, y) => x.YourNullableType.Value.CompareTo(y.YourNullableType.Value));