posts - 315, comments - 268, trackbacks - 15

My Links

News

View Pietro Libro's profile on LinkedIn

DomusDotNet
   DomusDotNet

Pietro Libro

Tag Cloud

Article Categories

Archives

Post Categories

Blogs amici

Links

OrderBy (e OrderByDescending) e comparatori personalizzati

Supponiamo di lavorare con due classi del tipo seguente:

image

e di voler utilizzare Linq To Objects per eseguire delle operazioni sul nostro insieme di dati, composto da un array di oggetti Documento:

1 Documento[] documenti = new Documento[]{ 2 new Documento ("10",new Cliente {Nome="Pietro",Cognome ="Libro",CodiceFiscale="ABA"}), 3 new Documento ("2",new Cliente {Nome="Pietro",Cognome ="Bianchi",CodiceFiscale="ABB"}), 4 new Documento ("1",new Cliente {Nome="Giuseppe",Cognome ="Rossi",CodiceFiscale="ABC"}), 5 new Documento ("1",new Cliente {Nome="Gabriele",Cognome ="Bianchi",CodiceFiscale="ABD"})};

Supponiamo di voler utilizzare una query expression per ottenere una lista (nello specifico un  oggetto che implementi l'interfaccia IEnumerable<T>, o IOrderedEnumerable<T> che estende IEnumerable<t>), che possa essere "esplorata" mediante uno statement foreach:

1 var result = 2 from d in documenti 3 orderby d.Numero 4 select d;

Eseguendo il tutto in un'applicazione console otterremmo:

image

Che non è proprio quello che ci aspettiamo dato che 2 viene prima di 10. Il problema nasce dal fatto che nel nostro modello ad oggetti, abbiamo definito il campo Numero, della classe Documento, come String. A questo punto potremmo optare tra almeno due soluzioni: procediamo con un refactoring del codice e cambiamo il tipo del membro Numero, o utilizziamo un overload dell'Extension Method OrderBy (o OrderByDescending). Più precisamente, utilizzeremo l'overload  seguente:

1 public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>( 2 this IEnumerable<TSource> source, 3 Func<TSource, TKey> keySelector, 4 IComparer<TKey> comparer 5 ) 6

Il quale esegue l'ordinamento  ascendente di una sequenza di dati utilizzando uno specifico Comparer. Nello specifico, questo sarà così definito:

1 public class DocumentoComparer : IComparer<Documento> 2 { 3 #region IComparer<Documento> Members 4 5 public int Compare(Documento x, Documento y) 6 { 7 if (x.Numero.Equals(y.Numero)) 8 { 9 //Ordina in base al nominativo del cliente 10 return string.Compare(x.Cliente.Cognome, y.Cliente.Cognome); 11 } 12 else 13 { 14 if (int.Parse(x.Numero) < int.Parse(y.Numero)) 15 return -1; 16 else 17 return 1; 18 } 19 } 20 21 #endregion 22 }

Nel caso in cui siano presenti due documenti con lo stesso numero, magari perchè di tipo diverso, l'ordinamento viene effettuato in base all'ordinamento lessicografico della proprietà Cognome del Cliente, altrimenti le stringhe Numero sono convertite nei rispettivi valori interi, quindi eseguito il confronto.

A questo punto, mediante method syntax, possiamo scrivere:

1 var resultMethod = 2 documenti 3 .OrderBy(d => d, new DocumentoComparer());

Ottenendo:

image 

Nel caso in cui non sia fornito un comparatore o che Comparer sia nullo verrà utilizzata la proprietà Default, di Comparer<T>, ovvero Comparer<TKey>.Default, ma se il tipo T (come ad esempio Documento) non implementa ne l'interfaccia IComparable<T> ne IComparable, in fase di esecuzione verrà generata un'eccezione.

Print | posted on venerdì 2 gennaio 2009 21:58 | Filed Under [ LINQ ]

Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET