Ordinamento generico di elenchi

5

Ho diversi elenchi < > che contiene oggetti di classi diverse.

List<classA> listA;
List<classB> listB;
List<classC> listC;
//...
List<classM> listM;

Le classi non sono correlate in alcun modo e non hanno nulla in comune tranne che potrebbero avere una singola proprietà contrassegnata con un attributo SortBy=true

    [CustomObjectComparerAttribute(IncludeInCompare = true, Title = "View Order", SortBy=true)]
    public int ViewOrder { get; set; }

Quello che mi piacerebbe fare è avere una funzione generica che accetti un elenco di qualsiasi tipo. Questo è il problema n. 1, perché non riesco a capire un modo per far sì che una funzione accetti le liste < > di diversi tipi.

private List<object> SortList(List<object> aList)  //<-- this is not allowed (problem 1)
{
    //Get which property we sort by...
    PropertyInfo  prop = GetPropertyToSortBy(objectA);

    //Sort the list
    //Problem Nr 2: How do I get 'PropertyInfo prop' in the statement below
    List<Order> SortedList = aList.OrderBy(o=>o.ThePropToSortBy).ToList();
}
    private PropertyInfo GetPropertyToSortBy(object o)
    {
        Type t = o.GetType();
        foreach (PropertyInfo prop in t.GetProperties(BindingFlags.Instance | BindingFlags.Public))
        {
            if (Attribute.IsDefined(prop, typeof(CustomObjectComparerAttribute)) && ((CustomObjectComparerAttribute)Attribute.GetCustomAttribute(prop, typeof(CustomObjectComparerAttribute))).SortBy == true)
            {
                return prop;
            }
        }
        return null;
    }

Sento che sto attaccando questo problema dall'angolo sbagliato. Sono sulla buona strada? E se sì, come posso risolvere i miei problemi?

se no, puoi indicarmi la direzione giusta?

    
posta David 26.06.2015 - 18:56
fonte

2 risposte

14

I tuoi problemi specifici sono risolti in modo relativamente semplice.

Problema 1 è solo un problema di sintassi per come scrivere metodi con parametri di tipo generico. Nel tuo caso questo sarebbe:

private List<T> SortList<T>(List<T> aList)

È il <T> dopo il nome del metodo che ti consente di utilizzare T come parametro di tipo generico nel resto della firma

Problema 2 richiede solo un po 'di oscuro scavo nelle classi di riflessione. Hai già un'istanza ProperyInfo , quindi devi solo utilizzare PropertyInfo.GetValue , documentato qui . In altre parole:

List<Order> SortedList = aList.OrderBy(o=>prop.GetValue(o)).ToList();

Incontrerai anche alcuni problemi secondari, ad esempio il riflesso è piuttosto lento e lo utilizzerai molte volte durante l'ordinamento. Le prestazioni spesso non sono una preoccupazione primaria, ma per qualcosa come ordinare una lista è potenzialmente importante. Non so in cima alla mia testa se fosse davvero un problema in questo caso ... ma per scoprirlo è necessario preoccuparsi di questo, della ricerca e di tutte quelle altre cose che preferireste semplicemente evitare del tutto.

Inoltre, è tutto piuttosto complesso! Ora per fare qualcosa di semplice come una lista, devi fare i conti con gli attributi, la riflessione e tutto ciò che muck.

La causa del percorso dei tuoi problemi è che stai cercando di esporre qualcosa che dovrebbe essere comportamento come metadata . Questa è una variante un po 'insolita di un problema più comune che emerge in OO design: esponendo qualcosa che dovrebbe essere un comportamento come data .

Fortunatamente, .NET ci offre già un buon modo per consentire a una classe di definire come dovrebbe essere ordinata sotto forma di comportamento: l'interfaccia IComparable<T> . Di nuovo, probabilmente stai meglio leggendo la documentazione , ma nel tuo caso, invece di scrivere:

public class SomeSortableThing
{
    [CustomObjectComparer]
    public int SortByMe {get; set;}
}

Scriveresti:

public class SomeSortableThing : IComparable<SomeSortableThing>
{
    public int SortByMe {get; set;}
    public int CompareTo(SomeSortableThing other)
    {
        return SortByMe.CompareTo(other.SortByMe);
    }
}

Questo ci dà i vantaggi:

  • Non c'è bisogno di riflessioni o attributi
  • È idiomatico
  • È facile da usare: qualsiasi consumatore può semplicemente utilizzare i metodi di ordinamento standard senza bisogno di alcun metodo / classe di supporto speciale
  • È molto più flessibile. Se vuoi ordinare per una proprietà o un'altra, puoi farlo facilmente, piuttosto che dover inventare un modo completamente nuovo di rappresentarlo attraverso gli attributi
  • Le nostre proprietà ordinabili non devono essere pubbliche, possono essere incapsulate se è appropriato.
  • Puoi ordinare in modo intercambiabile su proprietà e campi, senza doverlo supportare nel tuo riflesso.
risposta data 26.06.2015 - 19:13
fonte
0

.net fornisce SortedList classe in System.Collections.Generic che mantiene ordinato l'elenco. La tua classe TKey dovrà implementare IComparable o dovrà implementare un Comparatore per TKey.

Se la mia classe dovesse essere smistata nello stesso modo ogni volta, allora implementerei IComparable, ma se volessi a volte ordinare sulla stessa A poi B, ma altre volte dire C allora l'AI scriverà Comparer e passerà poi a SortedList.

SortedList è perfetto se si dispone di una raccolta di grandi dimensioni da controllare per vedere se esiste una chiave - L'elenco può diventare molto lento per questo tipo di operazioni. Tuttavia, SortedList sarà più lento per inserire valori in.

    
risposta data 27.06.2015 - 10:40
fonte

Leggi altre domande sui tag