proprietà - public property c# get set




Come ordinare una lista<T> da una proprietà nell'oggetto (13)

// Ordinamento completamente generico da utilizzare con un gridview

public List<T> Sort_List<T>(string sortDirection, string sortExpression, List<T> data)
    {

        List<T> data_sorted = new List<T>();

        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, string propName)
    {
        //Use reflection to get order type
        return item.GetType().GetProperty(propName).GetValue(item, null);
    }

Ho una classe chiamata Order che ha proprietà come OrderId , OrderId , Quantity e Total . Ho una lista di questa classe di Order :

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

Ora voglio ordinare l'elenco in base a una proprietà dell'oggetto Order , ad esempio ho bisogno di ordinarlo in base alla data dell'ordine o all'ID ordine.

Come posso farlo in C #?


Basato sul Comparatore di GenericTypeTea :
possiamo ottenere più flessibilità aggiungendo flag di ordinamento:

public class MyOrderingClass : IComparer<Order> {  
    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; }  
}  

In questo scenario, è necessario istanziarlo come MyOrderingClass in modo esplicito (piuttosto che IComparer )
per impostare le sue proprietà di classificazione:

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

Dal punto di vista delle prestazioni, il migliore è utilizzare una lista ordinata in modo che i dati vengano ordinati in base al risultato. Altri approcci richiedono almeno un'iterazione aggiuntiva sui dati e la maggior parte crea una copia dei dati, quindi non solo le prestazioni, ma anche l'utilizzo della memoria ne risentirà. Potrebbe non essere un problema con un paio di centinaia di elementi, ma sarà con migliaia, soprattutto nei servizi in cui molte richieste simultanee possono fare lo smistamento allo stesso tempo. Dai uno sguardo allo spazio dei nomi System.Collections.Generic e scegli una classe con l'ordinamento invece di Elenco.

Evitare implementazioni generiche utilizzando la riflessione quando possibile, questo può causare anche problemi di prestazioni.


Ecco un metodo di estensione LINQ generico che non crea una copia aggiuntiva dell'elenco:

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

Per usarlo:

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

Di recente ho creato questo aggiuntivo che accetta un ICompare<U> , in modo da poter personalizzare il confronto. Questo è stato utile quando ho avuto bisogno di fare una sorta di stringa naturale:

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

Il modo più semplice a cui riesco a pensare è usare Linq:

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

Il modo più semplice per ordinare un elenco è utilizzare OrderBy

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

Se si desidera ordinare per più colonne come seguendo SQL Query.

ORDER BY OrderDate, OrderId

Per raggiungere questo obiettivo, puoi utilizzare ThenBy come segue.

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

Per farlo senza LINQ su .Net2.0:

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

Se sei su .Net3.0, la answer di LukeH è ciò che cerchi.

Per ordinare su più proprietà, puoi ancora farlo all'interno di un delegato. Per esempio:

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;
    }
);

Questo ti darebbe date ascendenti con ordini decrescenti .

Tuttavia, non consiglierei di attaccare i delegati poiché significherebbe molti posti senza riutilizzo del codice. Dovresti implementare un IComparer e trasferirlo nel tuo metodo Sort . Vedi here

public class MyOrderingClass : IComparer<Order>
{
    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;
    }
}

Quindi, per utilizzare questa classe IComparer, basta istanziarla e passarla al metodo Sort:

IComparer<Order> comparer = new MyOrderingClass();
orderList.Sort(comparer);

Per favore lasciatemi completare la risposta di @LukeH con un codice di esempio, poiché l'ho provato credo che possa essere utile per alcuni:

public class Order
{
    public string OrderId { get; set; }
    public DateTime OrderDate { get; set; }
    public int Quantity { get; set; }
    public int Total { get; set; }

    public Order(string orderId, DateTime orderDate, int quantity, int total)
    {
        OrderId = orderId;
        OrderDate = orderDate;
        Quantity = quantity;
        Total = total;
    }
}

public void SampleDataAndTest()
{
    List<Order> objListOrder = new List<Order>();

    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.ToString() + " 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.ToString() + " 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.ToString() + " Quantity = " + o.Quantity + " Total = " + o.Total);

    //etc ...
}

Se è necessario ordinare l'elenco sul posto, è possibile utilizzare il metodo Sort , passando un delegato di Comparison<T> :

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

Se si preferisce creare una sequenza nuova, ordinata piuttosto che ordinare sul posto, è possibile utilizzare il metodo OrderBy di LINQ, come menzionato nelle altre risposte.


Un miglioramento della versione di Roger.

Il problema con GetDynamicSortProperty è che ottengono solo i nomi delle proprietà ma cosa succede se nel GridView usiamo NavigationProperties? invierà un'eccezione, poiché trova nulla.

Esempio:

"Employee.Company.Name;" si arresta in modo anomalo ... poiché consente solo il "Nome" come parametro per ottenere il suo valore.

Ecco una versione migliorata che ci consente di ordinare per Proprietà di navigazione.

public object GetDynamicSortProperty(object item, string propName)
    {
        try
        {                 
            string[] 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;
        }


    } 

Utilizzando LINQ

objListOrder = GetOrderList()
                   .OrderBy(o => o.OrderDate)
                   .ToList();

objListOrder = GetOrderList()
                   .OrderBy(o => o.OrderId)
                   .ToList();

Una soluzione classica orientata agli oggetti

Per prima cosa devo genuflessi alla bellezza di LINQ ... Ora che ce l'abbiamo tolta

Una variazione sulla risposta di JimmyHoffa. Con i generici il parametro CompareTo diventa sicuro.

public class Order : IComparable<Order> {

    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<Order>
myOrders.Sort(); 

Questa sorta di default è ovviamente riutilizzabile. Questo è il motivo per cui ogni cliente non deve riscrivere in modo ridondante la logica di ordinamento. Scambiando "1" e "-1" (o gli operatori logici, a tua scelta) si inverte l'ordinamento.


var obj = db.Items.Where...

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




sorting